Pergunta

Em Mathematica Eu tenho uma lista:

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

Como vou fazer uma lista com as duplicatas? Como:

{3,5}

Eu tenho estado a olhar para listas como conjuntos , se há algo como exceto [] para as listas, para que eu pudesse fazer:

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

(É claro que, se o x teria mais de duas duplicatas - digamos, {1, 2,2,2 , 3,4,4}, há a saída seria {2, 2,4}, mas União adicional [] resolveria isso.)

Mas não havia qualquer coisa assim (se eu entendi todas as funções lá também).

Então, como fazer isso?

Foi útil?

Solução

Muitas maneiras de fazer lista de extração como esta; aqui está a primeira coisa que veio à minha mente:

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

Ou, mais legível em pedaços:

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

que dá, respectivamente,

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

Talvez você pode pensar de uma maneira mais eficiente (em tempo ou espaço de código) :)

A propósito, se a lista é não separados, então você precisa executar Sort sobre ele antes de este trabalho.

Outras dicas

Aqui está uma maneira de fazê-lo em uma única passagem através da lista:

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

Por exemplo:

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

Se você deseja que a lista de duplicatas únicos - {1, 4, 2} -. Em seguida, enrole o acima em DeleteDuplicates, que é outra única passagem através da lista (Union é menos eficiente como também classifica o resultado)

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

A solução de Will Robertson é provavelmente melhor só porque é mais simples, mas acho que se você quisesse espremer mais velocidade, este deve ganhar. Mas se você se importava com isso, você não estaria programando em Mathematica! :)

Aqui estão alguns mais rápido variações do método Tally.

usos f4 "truques" dadas por Carl Woll e Oliver Ruebenkoenig no grupo matemático.

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

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

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

comparação Speed ??(f1 incluído para referência)

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

É incrível para mim que f4 tem quase nenhuma despesa relativa a um Tally pura!

Usando uma solução como dreeves, mas apenas retornando uma única instância de cada elemento duplicado, é um pouco sobre o lado complicado. Uma maneira de fazer isso é o seguinte:

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

Esta não corresponde precisamente a saída produzida pela solução de Will Robertson (IMO Superior), porque os elementos aparecerão na lista retornada na ordem em que ele pode ser determinado que eles são duplicatas. Eu não tenho certeza se ele realmente pode ser feito em uma única passagem, todas as maneiras que eu posso pensar de envolver, com efeito, pelo menos duas passagens, embora um pode ser apenas sobre os elementos duplicados.

Aqui está uma versão da resposta de Robertson que utiliza 100% "notação postfix" para chamadas de função.

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

// do Mathematica é semelhante ao ponto para chamadas de método em outros idiomas. Por exemplo, se este foram escritos em C estilo # / LINQ, ele seria parecido com

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

Note que o C # 'Where s é como Select do MMA, e C #' Select s é como Map do MMA.

EDIT:. Adicionado argumento função de teste opcional, padronizando a SameQ

EDIT: aqui está uma versão que endereços meu comentário abaixo e relata todos os equivalentes em um grupo que recebeu uma função de projetor que produz um valor tal que elementos da lista são consideradas equivalentes se o valor é igual. Isto essencialmente encontra classes de equivalência mais do que um determinado tamanho:

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

Aqui é um exemplo que verifica pares de inteiros em seus primeiros elementos, considerando dois pares equivalentes se os primeiros elementos são iguais

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

Esta discussão parece velha, mas eu tive que resolver isso sozinho.

Esta é uma espécie de bruto, mas faz isso fazê-lo?

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

Dada uma lista A,
obter os valores não-duplicados em B
B = DeleteDuplicates [A]
obter os valores duplicados em C
C = Complemento [A, B]
obter os valores não-duplicados da lista duplicado em D
D = DeleteDuplicates [C]

Assim, para o seu exemplo:
A = 1, 2, 2, 2, 3, 4, 4
B = 1, 2, 3, 4
C = 2, 2, 4
D = 2, 4

para que a sua resposta seria DeleteDuplicates [Complemento [x, DeleteDuplicates [x]]] onde x é a sua lista. Eu não sei mathematica, de modo a sintaxe pode ou não ser perfeito aqui. Basta ir pelas docs na página ligado a você.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top