Praticamente preciso escrever um programa para verificar se uma lista possui duplicatas e, se houver, as remove e retorna uma nova lista com os itens que não foram duplicados / removidos. É isso que tenho, mas para ser sincero, não sei o que fazer.
def remove_duplicates():
t = ['a', 'b', 'c', 'd']
t2 = ['a', 'c', 'd']
for t in t2:
t.append(t.remove())
return t
python
algorithm
list
duplicates
intersection
Neemaximo
fonte
fonte
Respostas:
A abordagem comum para obter uma coleção exclusiva de itens é usar a
set
. Conjuntos são coleções não ordenadas de objetos distintos . Para criar um conjunto a partir de qualquer iterável, você pode simplesmente transmiti-lo para aset()
função interna. Se mais tarde você precisar de uma lista real novamente, poderá passar o conjunto da mesma forma para alist()
função.O exemplo a seguir deve cobrir o que você está tentando fazer:
Como você pode ver no resultado do exemplo, o pedido original não é mantido . Como mencionado acima, os conjuntos são coleções não ordenadas e, portanto, o pedido é perdido. Ao converter um conjunto de volta em uma lista, uma ordem arbitrária é criada.
Manutenção da ordem
Se a ordem é importante para você, você terá que usar um mecanismo diferente. Uma solução muito comum para isso é
OrderedDict
manter a ordem das chaves durante a inserção:A partir do Python 3.7 , é garantido que o dicionário interno também mantenha a ordem de inserção, para que você também possa usá-lo diretamente se estiver no Python 3.7 ou posterior (ou CPython 3.6):
Observe que isso pode ter alguma sobrecarga na criação de um dicionário primeiro e, em seguida, na criação de uma lista. Se você realmente não precisa preservar o pedido, geralmente é melhor usar um conjunto, especialmente porque ele oferece muito mais operações para trabalhar. Confira esta pergunta para obter mais detalhes e formas alternativas de preservar o pedido ao remover duplicatas.
Por fim, observe que tanto as soluções
set
quanto asOrderedDict
/dict
requerem que seus itens sejam laváveis . Isso geralmente significa que eles precisam ser imutáveis. Se você precisar lidar com itens que não são laváveis (por exemplo, listar objetos), precisará usar uma abordagem lenta na qual basicamente precisará comparar todos os itens com todos os outros itens em um loop aninhado.fonte
No Python 2.7 , a nova maneira de remover duplicatas de um iterável, mantendo-o na ordem original é:
No Python 3.5 , o OrderedDict tem uma implementação em C. Meus horários mostram que agora é a mais rápida e a mais curta das várias abordagens para o Python 3.5.
No Python 3.6 , o ditado regular tornou-se ordenado e compacto. (Esse recurso é válido para CPython e PyPy, mas pode não estar presente em outras implementações). Isso nos fornece uma nova maneira mais rápida de desduplicar, mantendo a ordem:
No Python 3.7 , o dict regular é garantido para ambos ordenados em todas as implementações. Portanto, a solução mais curta e rápida é:
fonte
TypeError: unhashable type: 'dictlist'
É uma linha:
list(set(source_list))
fará o truque.A
set
é algo que não pode ter duplicatas.Atualização: uma abordagem de preservação de pedidos é de duas linhas:
Aqui, usamos o fato de
OrderedDict
lembrar a ordem de inserção das chaves e não a altera quando um valor em uma chave específica é atualizado. Nós inserimosTrue
como valores, mas podemos inserir qualquer coisa, valores simplesmente não são usados. (set
funciona muito parecidodict
com um com valores ignorados também.)fonte
source_list
for lavável.fonte
frozenset
funciona com conteúdo não-lavável. Ainda estou recebendo o erro não-lavável ao usarfrozenset
.Se você não se importa com o pedido, faça o seguinte:
A
set
é garantido para não ter duplicatas.fonte
l
seja lavável.Para criar uma nova lista mantendo a ordem dos primeiros elementos das duplicatas em
L
newlist=[ii for n,ii in enumerate(L) if ii not in L[:n]]
por exemplo,
if L=[1, 2, 2, 3, 4, 2, 4, 3, 5]
entãonewlist
será[1,2,3,4,5]
Isso verifica se cada novo elemento não apareceu anteriormente na lista antes de adicioná-lo. Também não precisa de importações.
fonte
set
eOrderedDict
podem ter menor complexidade de tempo amortizado.Um colega me enviou a resposta aceita como parte de seu código para uma revisão de código hoje. Embora certamente admire a elegância da resposta em questão, não estou feliz com o desempenho. Eu tentei esta solução (eu uso o set para reduzir o tempo de pesquisa)
Para comparar a eficiência, usei uma amostra aleatória de 100 números inteiros - 62 eram únicos
Aqui estão os resultados das medições
Bem, o que acontece se o conjunto for removido da solução?
O resultado não é tão ruim quanto no OrderedDict , mas ainda mais do que 3 vezes a solução original
fonte
def unique(iterable):
:;seen = set()
;seen_add = seen.add
;return [item for item in iterable if not item in seen and not seen_add(item)]
Existem também soluções usando Pandas e Numpy. Ambos retornam uma matriz numpy, então você precisa usar a função
.tolist()
se quiser uma lista.Solução Pandas
Usando a função Pandas
unique()
:Solução Numpy
Usando a função numpy
unique()
.Observe que numpy.unique () também classifica os valores . Portanto, a lista
t2
é retornada classificada. Se você deseja preservar o pedido, use esta resposta :A solução não é tão elegante em comparação com as outras, no entanto, em comparação com pandas.unique (), numpy.unique () permite também verificar se as matrizes aninhadas são únicas ao longo de um eixo selecionado.
fonte
Outra maneira de fazer:
fonte
keys()
retorna um objeto de exibição de dicionário, não uma lista.Simples e fácil:
Resultado:
fonte
in
é O funcionamento (n) e seucleanlist
vai ter no máximon
números => pior caso ~ O (n ^ 2)Nesta resposta, haverá duas seções: Duas soluções exclusivas e um gráfico de velocidade para soluções específicas.
Removendo itens duplicados
A maioria dessas respostas remove apenas itens duplicados que podem ser lavados , mas essa pergunta não implica que ele não precise apenas de itens laváveis , o que significa que vou oferecer algumas soluções que não exigem itens laváveis .
O contador é uma ferramenta poderosa na biblioteca padrão que pode ser perfeita para isso. Existe apenas uma outra solução que possui o Counter. No entanto, essa solução também é limitada a chaves laváveis .
Para permitir chaves laváveis no contador, criei uma classe Container, que tentará obter a função hash padrão do objeto, mas se falhar, tentará sua função de identidade. Ele também define um método eq e hash . Isso deve ser suficiente para permitir itens laváveis em nossa solução. Os objetos unhas laváveis serão tratados como se fossem laváveis. No entanto, essa função de hash usa identidade para objetos laváveis, o que significa que dois objetos iguais que são laváveis não funcionarão. Eu sugiro que você substitua isso e altere-o para usar o hash de um tipo mutável equivalente (como usar
hash(tuple(my_list))
ifmy_list
é uma lista).Eu também fiz duas soluções. Outra solução que mantém a ordem dos itens, usando uma subclasse de OrderedDict e Counter, chamada 'OrderedCounter'. Agora, aqui estão as funções:
remd é uma classificação não ordenada, oremd é uma classificação ordenada. Você pode dizer claramente qual é o mais rápido, mas eu explicarei de qualquer maneira. A classificação não ordenada é um pouco mais rápida. Ele mantém menos dados, pois não precisa de ordem.
Agora, eu também queria mostrar as comparações de velocidade de cada resposta. Então, eu vou fazer isso agora.
Qual função é a mais rápida?
Para remover duplicatas, reuni 10 funções com algumas respostas. Calculei a velocidade de cada função e a coloquei em um gráfico usando matplotlib.pyplot .
Dividi isso em três rodadas de gráficos. Um hashable é qualquer objeto que possa ser hash, um unhashable é qualquer objeto que não possa ser hash. Uma sequência ordenada é uma sequência que preserva a ordem, uma sequência não ordenada não preserva a ordem. Agora, aqui estão mais alguns termos:
O Hashable desordenado era para qualquer método que removeu duplicatas, que não precisavam necessariamente manter o pedido. Não precisava trabalhar para unhashables, mas podia.
O Hashable ordenado era para qualquer método que mantivesse a ordem dos itens na lista, mas não precisava funcionar para unhashables, mas podia.
O pedido de Unhashable era qualquer método que mantivesse a ordem dos itens da lista e funcionasse para unhashables.
No eixo y é a quantidade de segundos que levou.
No eixo x é o número ao qual a função foi aplicada.
Geramos seqüências para hashables não ordenados e ordenamos hashables com a seguinte compreensão:
[list(range(x)) + list(range(x)) for x in range(0, 1000, 10)]
Para unhashables encomendadas:
[[list(range(y)) + list(range(y)) for y in range(x)] for x in range(0, 1000, 10)]
Observe que há um 'passo' no intervalo, porque sem ele, isso levaria 10 vezes mais. Também porque, na minha opinião pessoal, achei que poderia parecer um pouco mais fácil de ler.
Observe também que as teclas na legenda são o que tentei adivinhar como as partes mais vitais da função. Quanto a qual função faz o pior ou o melhor? O gráfico fala por si.
Com isso resolvido, aqui estão os gráficos.
Hashables não ordenados
(Mais zoom)
Hashables ordenados
(Mais zoom)
Encomendado Unhashables
(Mais zoom)
fonte
Eu tinha um ditado na minha lista, então não pude usar a abordagem acima. Eu recebi o erro:
Então, se você se importa com a ordem e / ou alguns itens são laváveis . Então você pode achar isso útil:
Alguns podem considerar a compreensão da lista com um efeito colateral não uma boa solução. Aqui está uma alternativa:
fonte
map
com um efeito colateral é ainda mais enganador do que um listcomp com efeito colateral. Além disso,lambda x: unique_list.append(x)
é apenas uma maneira mais lenta e desajeitada de passarunique_list.append
.Todas as abordagens de preservação de ordem que eu vi aqui até agora usam comparação ingênua (com O (n ^ 2) complexidade de tempo, na melhor das hipóteses) ou combinações de peso
OrderedDicts
/set
+list
limitadas a entradas hasháveis. Aqui está uma solução O (nlogn) independente de hash:A atualização adicionou o
key
argumento, a documentação e a compatibilidade com o Python 3.fonte
tuple()
e hash-las. | | | | - De um modo geral, o processo de hash leva um tempo proporcional ao tamanho de todos os dados, enquanto essa solução leva um tempo O (nlog (n)), dependendo apenas do comprimento da lista.reduce()
já está trabalhando em uma coleção classificadasrt_enum
, por que você se inscreveusorted
novamente?Se você deseja preservar o pedido e não usar nenhum módulo externo, aqui está uma maneira fácil de fazer isso:
Nota: Este método preserva a ordem de aparência, portanto, como visto acima, nove virão após um porque foi a primeira vez que apareceu. No entanto, esse é o mesmo resultado que você obteria ao fazer
mas é muito mais curto e corre mais rápido.
Isso funciona porque cada vez que a
fromkeys
função tenta criar uma nova chave, se o valor já existir, ela simplesmente a substituirá. No entanto, isso não afeta o dicionário, poisfromkeys
cria um dicionário em que todas as chaves têm o valorNone
; portanto, efetivamente elimina todas as duplicatas dessa maneira.fonte
Você também pode fazer isso:
A razão que funciona acima é que o
index
método retorna apenas o primeiro índice de um elemento. Elementos duplicados têm índices mais altos. Consulte aqui :fonte
list.index
é uma operação de tempo linear, tornando sua solução quadrática.Tente usar conjuntos:
fonte
Reduza a variante com a reserva de pedidos:
Suponha que tenhamos uma lista:
Reduzir variante (ineficiente):
5x mais rápido, mas mais sofisticado
Explicação:
fonte
A melhor abordagem para remover duplicatas de uma lista é usar a função set () , disponível em python, convertendo novamente esse conjunto em lista
fonte
Você pode usar a seguinte função:
Exemplo :
Uso:
['this', 'is', 'a', 'list', 'with', 'dupicates', 'in', 'o']
fonte
Existem muitas outras respostas sugerindo maneiras diferentes de fazer isso, mas todas são operações em lote, e algumas delas descartam o pedido original. Isso pode ser bom, dependendo do que você precisa, mas se você deseja iterar sobre os valores na ordem da primeira instância de cada valor e remover as duplicatas on-the-fly contra todas de uma só vez, poderá usar este gerador:
Isso retorna um gerador / iterador, para que você possa usá-lo em qualquer lugar que possa usar um iterador.
Resultado:
Se você deseja um
list
, pode fazer o seguinte:Resultado:
fonte
seen = set(iterable); for item in seen: yield item
é quase certamente mais rápido. (Eu não tentei este caso específico, mas isso seria o meu palpite.)Sem usar set
fonte
Você pode usar
set
para remover duplicatas:Mas observe que os resultados serão desordenados. Se isso é um problema:
fonte
Mais uma abordagem melhor poderia ser,
e a ordem permanece preservada.
fonte
Este se preocupa com o pedido sem muito trabalho (OrderdDict e outros). Provavelmente não é o caminho mais pitônico, nem o caminho mais curto, mas faz o truque:
fonte
list
); 2. Seu método é extremamente ruim: é quadrático no número de elementos emlist
.o código abaixo é simples para remover duplicados na lista
retorna [1,2,3,4]
fonte
list(set(..))
(mais de 1 milhão de passes) superará essa solução em cerca de 10 segundos inteiros - enquanto essa abordagem leva cerca de 12 segundos,list(set(..))
leva apenas 2 segundos!Aqui está a solução pitônica mais rápida comparada com outras listadas nas respostas.
O uso de detalhes de implementação da avaliação de curto-circuito permite usar a compreensão da lista, o que é rápido o suficiente.
visited.add(item)
sempre retornaNone
como resultado, que é avaliado comoFalse
, portanto, o lado direito deor
sempre seria o resultado dessa expressão.Time it yourself
fonte
Usando o conjunto :
Usando exclusivo :
fonte
Infelizmente. A maioria das respostas aqui não preserva o pedido ou é muito longa. Aqui está uma resposta simples e preservadora de pedidos.
Isso fornecerá x com duplicatas removidas, mas preservando o pedido.
fonte
Maneira muito simples em Python 3:
fonte
sorted(list(...))
é redundante (sorted
já converte implicitamente seu argumento em um novolist
, classifica-o e depois retorna o novolist
, portanto, usando os dois meios, torna temporário desnecessáriolist
). Use apenaslist
se o resultado não precisar ser classificado, use apenassorted
se o resultado precisar ser classificado.O tipo embutido Magic of Python
No python, é muito fácil processar casos complicados como esse e somente pelo tipo interno do python.
Deixe-me mostrar-lhe como fazer!
Método 1: caso geral
A maneira ( 1 código de linha ) de remover o elemento duplicado da lista e ainda manter a ordem de classificação
Você obterá o resultado
Método 2: caso especial
O caso especial para processar unhashable ( 3 códigos de linha )
Você obterá o resultado:
Como a tupla é lavável e você pode converter dados entre lista e tupla facilmente
fonte