Mostra duplicati in Mathematica
-
06-07-2019 - |
Domanda
In Mathematica ho un elenco:
x = {1,2,3,3,4,5,5,6}
Come farò un elenco con i duplicati? Come:
{3,5}
Ho guardato Liste come set , se c'è qualcosa come Tranne [] per gli elenchi, quindi potrei fare:
unique = Union[x]
duplicates = MyExcept[x,unique]
(Naturalmente, se la x avesse più di due duplicati, ad esempio {1, 2,2,2 , 3,4,4}, l'output sarebbe {2, 2,4}, ma un'ulteriore Unione [] risolverebbe questo problema.)
Ma non c'era niente del genere (se avessi capito bene tutte le funzioni).
Quindi, come si fa?
Soluzione
Molti modi per estrarre la lista in questo modo; ecco la prima cosa che mi è venuta in mente:
Part[Select[Tally@x, Part[#, 2] > 1 &], All, 1]
O, più facilmente in pezzi:
Tally@x Select[%, Part[#, 2] > 1 &] Part[%, All, 1]
che dà, rispettivamente,
{{1, 1}, {2, 1}, {3, 2}, {4, 1}, {5, 2}, {6, 1}} {{3, 2}, {5, 2}} {3, 5}
Forse puoi pensare a un modo più efficiente (nel tempo o nello spazio del codice) :)
A proposito, se l'elenco non è ordinato, è necessario eseguire Ordina
prima che funzioni.
Altri suggerimenti
Ecco un modo per farlo in un unico passaggio attraverso l'elenco:
collectDups[l_] := Block[{i}, i[n_]:= (i[n] = n; Unevaluated@Sequence[]); i /@ l]
Ad esempio:
collectDups[{1, 1, 6, 1, 3, 4, 4, 5, 4, 4, 2, 2}] --> {1, 1, 4, 4, 4, 2}
Se si desidera l'elenco di duplicati univoci - {1, 4, 2}
- quindi avvolgere quanto sopra in DeleteDuplicates
, che è un altro passaggio singolo attraverso list ( Union
è meno efficiente in quanto ordina anche il risultato).
collectDups[l_] :=
DeleteDuplicates@Block[{i}, i[n_]:= (i[n] = n; Unevaluated@Sequence[]); i /@ l]
La soluzione di Will Robertson è probabilmente migliore solo perché è più semplice, ma penso che se volessi aumentare la velocità, questo dovrebbe vincere. Ma se ti importasse di questo, non saresti programmatore in Mathematica! :)
Ecco alcune varianti più veloci del metodo Tally.
f4
usa " trucchi " offerto da Carl Woll e Oliver Ruebenkoenig su MathGroup.
f2 = Tally@# /. {{_, 1} :> Sequence[], {a_, _} :> a} &;
f3 = Pick[#, Unitize[#2 - 1], 1] & @@ Transpose@Tally@# &;
f4 = # ~Extract~ SparseArray[Unitize[#2 - 1]]["NonzeroPositions"] & @@ Transpose@Tally@# &;
Confronto velocità ( f1
incluso come riferimento)
a = RandomInteger[100000, 25000];
f1 = Part[Select[Tally@#, Part[#, 2] > 1 &], All, 1] &;
First@Timing@Do[#@a, {50}] & /@ {f1, f2, f3, f4, Tally}
SameQ @@ (#@a &) /@ {f1, f2, f3, f4}
Out[]= {3.188, 1.296, 0.719, 0.375, 0.36}
Out[]= True
È sorprendente per me che f4
non abbia quasi alcun sovraccarico rispetto a un Tally
puro!
L'uso di una soluzione come dreeves, ma restituendo solo una singola istanza di ciascun elemento duplicato, è un po 'complicato. Un modo per farlo è il seguente:
collectDups1[l_] :=
Module[{i, j},
i[n_] := (i[n] := j[n]; Unevaluated@Sequence[]);
j[n_] := (j[n] = Unevaluated@Sequence[]; n);
i /@ l];
Questo non corrisponde esattamente all'output prodotto dalla soluzione di Will Robertson (IMO superiore), poiché gli elementi appariranno nell'elenco restituito nell'ordine in cui è possibile determinare che sono duplicati. Non sono sicuro che si possa davvero fare in un singolo passaggio, tutti i modi in cui riesco a pensare coinvolgono, in effetti, almeno due passaggi, anche se uno potrebbe essere solo sugli elementi duplicati.
Ecco una versione della risposta di Robertson che utilizza il 100% di "postfix notation" per chiamate di funzione.
identifyDuplicates[list_List, test_:SameQ] :=
list //
Tally[#, test] & //
Select[#, #[[2]] > 1 &] & //
Map[#[[1]] &, #] &
Il //
di Mathematica è simile al punto per le chiamate di metodo in altre lingue. Ad esempio, se questo fosse scritto in stile C # / LINQ, sarebbe simile
list.Tally(test).Where(x => x[2] > 1).Select(x => x[1])
Nota che di C # dove
è come Select
di M # e Select
di C # è come Map
di MMA.
EDIT: aggiunto l'argomento della funzione di test opzionale, il cui valore predefinito è SameQ
.
EDIT: ecco una versione che risponde al mio commento qui sotto & amp; riporta tutti gli equivalenti in un gruppo data una funzione del proiettore che produce un valore tale che gli elementi dell'elenco sono considerati equivalenti se il valore è uguale. Questo essenzialmente trova classi di equivalenza più lunghe di una data dimensione:
reportDuplicateClusters[list_List, projector_: (# &),
minimumClusterSize_: 2] :=
GatherBy[list, projector] //
Select[#, Length@# >= minimumClusterSize &] &
Ecco un esempio che controlla le coppie di numeri interi sui loro primi elementi, considerando due coppie equivalenti se i loro primi elementi sono uguali
reportDuplicateClusters[RandomInteger[10, {10, 2}], #[[1]] &]
Questo thread sembra vecchio, ma ho dovuto risolverlo da solo.
Questo è un po 'rozzo, ma lo fa?
Union[Select[Table[If[tt[[n]] == tt[[n + 1]], tt[[n]], ""], {n, Length[tt] - 1}], IntegerQ]]
Dato un elenco A,
ottenere i valori non duplicati in B
B = DeleteDuplicates [A]
ottenere i valori duplicati in C
C = Complemento [A, B]
ottenere i valori non duplicati dall'elenco duplicato in D
D = DeleteDuplicates [C]
Quindi, per il tuo esempio:
A = 1, 2, 2, 2, 3, 4, 4
B = 1, 2, 3, 4
C = 2, 2, 4
D = 2, 4
quindi la tua risposta sarebbe DeleteDuplicates [Complemento [x, DeleteDuplicates [x]]] dove x è il tuo elenco. Non conosco la matematica, quindi la sintassi può essere o non essere perfetta qui. Basta andare dai documenti sulla pagina a cui ti sei collegato.