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?

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top