Pregunta

En Mathematica tengo una lista:

x = {1,2,3,3,4,5,5,6}

¿Cómo haré una lista con los duplicados? Me gusta:

{3,5}

He estado mirando Listas como conjuntos , si hay algo como Excepto [] para las listas, por lo que podría hacer:

unique = Union[x]
duplicates = MyExcept[x,unique]

(Por supuesto, si la x tuviera más de dos duplicados, por ejemplo, {1, 2,2,2 , 3,4,4}, allí la salida sería {2, 2,4}, pero la Unión adicional [] resolvería esto.)

Pero no había nada de eso (si entendía bien todas las funciones allí).

Entonces, ¿cómo hacer eso?

¿Fue útil?

Solución

Muchas formas de hacer una extracción de listas como esta; Esto es lo primero que me vino a la mente:

Part[Select[Tally@x, Part[#, 2] > 1 &], All, 1]

O, más legible en piezas:

Tally@x
Select[%, Part[#, 2] > 1 &]
Part[%, All, 1]

que da, respectivamente,

{{1, 1}, {2, 1}, {3, 2}, {4, 1}, {5, 2}, {6, 1}}
{{3, 2}, {5, 2}}
{3, 5}

Quizás pueda pensar en una forma más eficiente (en tiempo o espacio de código) :)

Por cierto, si la lista no está ordenada, entonces debe ejecutar Ordenar antes de que esto funcione.

Otros consejos

Aquí hay una manera de hacerlo en una sola pasada por la lista:

collectDups[l_] := Block[{i}, i[n_]:= (i[n] = n; Unevaluated@Sequence[]); i /@ l]

Por ejemplo:

collectDups[{1, 1, 6, 1, 3, 4, 4, 5, 4, 4, 2, 2}] --> {1, 1, 4, 4, 4, 2}

Si desea la lista de duplicados únicos - {1, 4, 2} - luego envuelva lo anterior en DeleteDuplicates , que es otra pasada única a través del list ( Union es menos eficiente ya que también ordena el resultado).

collectDups[l_] := 
  DeleteDuplicates@Block[{i}, i[n_]:= (i[n] = n; Unevaluated@Sequence[]); i /@ l]

La solución de Will Robertson probablemente sea mejor solo porque es más sencilla, pero creo que si desea obtener más velocidad, esto debería ganar. Pero si te importara eso, ¡no estarías programando en Mathematica! :)

Aquí hay varias variaciones más rápidas del método Tally.

f4 usa " trucos " impartido por Carl Woll y Oliver Ruebenkoenig en MathGroup.

f2 = Tally@# /. {{_, 1} :> Sequence[], {a_, _} :> a} &;

f3 = Pick[#, Unitize[#2 - 1], 1] & @@ Transpose@Tally@# &;

f4 = # ~Extract~ SparseArray[Unitize[#2 - 1]]["NonzeroPositions"] & @@ Transpose@Tally@# &;

Comparación de velocidad ( f1 incluido como referencia)

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

¡Es sorprendente para mí que f4 casi no tenga sobrecarga en relación con un Tally puro!

Usar una solución como dreeves, pero solo devolver una sola instancia de cada elemento duplicado, es un poco complicado. Una forma de hacerlo es la siguiente:

collectDups1[l_] :=
  Module[{i, j},
    i[n_] := (i[n] := j[n]; Unevaluated@Sequence[]);
    j[n_] := (j[n] = Unevaluated@Sequence[]; n);
    i /@ l];

Esto no coincide exactamente con el resultado producido por la solución de Will Robertson (IMO superior), porque los elementos aparecerán en la lista devuelta en el orden en que se puede determinar que son duplicados. No estoy seguro de si realmente se puede hacer en una sola pasada, todas las formas en que puedo pensar implican, en efecto, al menos dos pasadas, aunque una podría estar solo sobre los elementos duplicados.

Aquí hay una versión de la respuesta de Robertson que utiliza el 100% de "notación postfix" para llamadas a funciones.

identifyDuplicates[list_List, test_:SameQ] :=
 list //
    Tally[#, test] & //
   Select[#, #[[2]] > 1 &] & //
  Map[#[[1]] &, #] &

El // de Mathematica es similar al punto para las llamadas a métodos en otros idiomas. Por ejemplo, si esto se escribiera en estilo C # / LINQ, se parecería a

list.Tally(test).Where(x => x[2] > 1).Select(x => x[1])

Tenga en cuenta que de C # donde es como Select de MMA, y Select de C # es como Map de MMA.

EDITAR: argumento de función de prueba opcional agregado, predeterminado en SameQ .

EDITAR: aquí hay una versión que aborda mi comentario a continuación & amp; informa todos los equivalentes en un grupo dada una función de proyector que produce un valor tal que los elementos de la lista se consideran equivalentes si el valor es igual. Esto esencialmente encuentra clases de equivalencia más largas que un tamaño dado:

reportDuplicateClusters[list_List, projector_: (# &), 
  minimumClusterSize_: 2] :=
 GatherBy[list, projector] //
  Select[#, Length@# >= minimumClusterSize &] &

Aquí hay una muestra que verifica pares de enteros en sus primeros elementos, considerando dos pares equivalentes si sus primeros elementos son iguales

reportDuplicateClusters[RandomInteger[10, {10, 2}], #[[1]] &]

Este hilo parece viejo, pero tuve que resolverlo yo mismo.

Esto es algo crudo, pero ¿lo hace?

Union[Select[Table[If[tt[[n]] == tt[[n + 1]], tt[[n]], ""], {n, Length[tt] - 1}], IntegerQ]]

Dada una lista A,
obtener los valores no duplicados en B
B = DeleteDuplicates [A]
obtener los valores duplicados en C
C = Complemento [A, B]
obtener los valores no duplicados de la lista duplicada en D
D = DeleteDuplicates [C]

Entonces, para su ejemplo:
A = 1, 2, 2, 2, 3, 4, 4
B = 1, 2, 3, 4
C = 2, 2, 4
D = 2, 4

entonces su respuesta sería DeleteDuplicates [Complement [x, DeleteDuplicates [x]]] donde x es su lista. No sé Mathica, por lo que la sintaxis puede o no ser perfecta aquí. Simplemente vaya a los documentos de la página a la que se vinculó.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top