Removendo duplicatas em listas


997

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

22
Sua descrição diz que você verifica "uma lista" em busca de duplicatas, mas seu código verifica duas listas.
Brendan Long


* using set: list (set (ELEMENTS_LIST)) * using dictionary: list (dict.fromkeys (ELEMENTS_LIST))
Shayan Amani

Respostas:


1642

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 a set()função interna. Se mais tarde você precisar de uma lista real novamente, poderá passar o conjunto da mesma forma para a list()função.

O exemplo a seguir deve cobrir o que você está tentando fazer:

>>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> t
[1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> list(set(t))
[1, 2, 3, 5, 6, 7, 8]
>>> s = [1, 2, 3]
>>> list(set(t) - set(s))
[8, 5, 6, 7]

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 é OrderedDictmanter a ordem das chaves durante a inserção:

>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]

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):

>>> list(dict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]

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 setquanto as OrderedDict/ dictrequerem 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.


4
Isso não funciona para os elementos da lista unhashable (por exemplo, uma lista de listas)
KNejad

3
@KNejad É o que afirma o último parágrafo.
poke

Oh oops. Deveria ter lido a coisa toda. O que acabei fazendo foi usar tuplas em vez de listas, para que essa abordagem ainda funcionasse.
KNejad 21/09/19

adicione isso ao exemplo, t = [3, 2, 1, 1, 2, 5, 6, 7, 8] mostra a diferença claramente!
sailfish009

"... sobrecarga de criar um dicionário primeiro ... Se você realmente não precisa preservar a ordem, é melhor usar um conjunto." - Eu perfilei isso porque estava curioso para saber se era verdade. Meus tempos mostram que, de fato, o conjunto é um pouco mais rápido: 1,12 µs por loop (conjunto) vs 1,53 µs por loop (dict) em loops de 1M com uma diferença de tempo absoluta de cerca de 4s em iterações de 1M. Portanto, se você estiver fazendo isso em um loop interno apertado, pode se importar, caso contrário, provavelmente não.
millerdev 9/12/19

414

No Python 2.7 , a nova maneira de remover duplicatas de um iterável, mantendo-o na ordem original é:

>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

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:

>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

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 é:

>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

10
Eu acho que essa é a única maneira de manter os itens em ordem.
Herberth Amaral

19
@HerberthAmaral: Isso está muito longe de ser verdade, consulte Como você remove duplicatas de uma lista em Python enquanto preserva a ordem?
Martijn Pieters

5
@MartijnPieters Correcting: Eu acho que essa é a única maneira simples de manter os itens em ordem.
Herberth Amaral

12
Por isso, também, o conteúdo da lista original deve ser Hashable
Davide

Como o @Davide mencionou, a lista original deve ser lavável. Isso significa que isso não funciona para uma lista de dicionários. TypeError: unhashable type: 'dictlist'
CraZ 16/05

187

É 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:

from collections import OrderedDict
OrderedDict((x, True) for x in source_list).keys()

Aqui, usamos o fato de OrderedDictlembrar a ordem de inserção das chaves e não a altera quando um valor em uma chave específica é atualizado. Nós inserimos Truecomo valores, mas podemos inserir qualquer coisa, valores simplesmente não são usados. ( setfunciona muito parecido dictcom um com valores ignorados também.)


5
Isso só funciona se source_listfor lavável.
Adrian Keister

@AdrianKeister: Isso é verdade. Existem objetos que têm semântica de igualdade razoável, mas não são hashable, por exemplo, listas. OTOH, se não pudermos ter um atalho como um hastable, terminamos com um algoritmo quadrático de apenas comparar todos os elementos com todos os elementos únicos atualmente conhecidos. Isso pode ser totalmente aceitável para entradas curtas, especialmente com muitas duplicatas.
9000

Certo exatamente. Eu acho que sua resposta seria de maior qualidade se você levasse esse caso de uso muito comum em consideração.
Adrian Keister

95
>>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> t
[1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> s = []
>>> for i in t:
       if i not in s:
          s.append(i)
>>> s
[1, 2, 3, 5, 6, 7, 8]

33
Observe que esse método funciona no tempo O (n ^ 2) e, portanto, é muito lento em listas grandes.
dotancohen

@ Chris_Rands: Não tenho certeza se frozensetfunciona com conteúdo não-lavável. Ainda estou recebendo o erro não-lavável ao usar frozenset.
Adrian Keister

85

Se você não se importa com o pedido, faça o seguinte:

def remove_duplicates(l):
    return list(set(l))

A seté garantido para não ter duplicatas.


3
Não funciona, a menos que lseja lavável.
Adrian Keister

41

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ão newlistserá[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.


3
Isso tem uma complexidade de tempo de O (n ^ 2) . As respostas com sete OrderedDictpodem ter menor complexidade de tempo amortizado.
blubberdiblub

Eu usei no meu código esta solução e funcionou muito bem, mas acho que é demorado
Gerasimos Ragavanis

@blubberdiblub, você pode explicar que mecanismo mais eficiente de código existe no set e no OrderedDict que poderia torná-los menos demorados? (excluindo as despesas gerais de carregá-los)
ilias iliadis 14/01/19

@iliasiliadis As implementações usuais de set e dict usam hashes ou (de alguma forma equilibrada) árvores. Você deve considerar construir o conjunto ou ditado e pesquisá-lo (várias vezes), mas sua complexidade amortizada geralmente ainda é menor que O (n ^ 2) . "Amortizado" em termos simples significa, em média (eles podem ter piores casos com maior complexidade que o caso médio). Isso é relevante apenas quando você possui um grande número de itens.
precisa saber é o seguinte

25

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)

def ordered_set(in_list):
    out_list = []
    added = set()
    for val in in_list:
        if not val in added:
            out_list.append(val)
            added.add(val)
    return out_list

Para comparar a eficiência, usei uma amostra aleatória de 100 números inteiros - 62 eram únicos

from random import randint
x = [randint(0,100) for _ in xrange(100)]

In [131]: len(set(x))
Out[131]: 62

Aqui estão os resultados das medições

In [129]: %timeit list(OrderedDict.fromkeys(x))
10000 loops, best of 3: 86.4 us per loop

In [130]: %timeit ordered_set(x)
100000 loops, best of 3: 15.1 us per loop

Bem, o que acontece se o conjunto for removido da solução?

def ordered_set(inlist):
    out_list = []
    for val in inlist:
        if not val in out_list:
            out_list.append(val)
    return out_list

O resultado não é tão ruim quanto no OrderedDict , mas ainda mais do que 3 vezes a solução original

In [136]: %timeit ordered_set(x)
10000 loops, best of 3: 52.6 us per loop

Bom usando a pesquisa rápida definida para acelerar a comparação em loop. Se a ordem não importa lista (set (x)) ainda é 6x mais rápido do que este
Joop

@ Joop, essa foi minha primeira pergunta para meu colega - a ordem importa; caso contrário, teria sido um problema trivial
volcano

versão otimizada do conjunto ordenado, para quem estiver interessado 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)]
DrD 16/02

25

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.

t=['a','a','b','b','b','c','c','c']
t2= ['c','c','b','b','b','a','a','a']

Solução Pandas

Usando a função Pandas unique():

import pandas as pd
pd.unique(t).tolist()
>>>['a','b','c']
pd.unique(t2).tolist()
>>>['c','b','a']

Solução Numpy

Usando a função numpy unique().

import numpy as np
np.unique(t).tolist()
>>>['a','b','c']
np.unique(t2).tolist()
>>>['a','b','c']

Observe que numpy.unique () também classifica os valores . Portanto, a lista t2é retornada classificada. Se você deseja preservar o pedido, use esta resposta :

_, idx = np.unique(t2, return_index=True)
t2[np.sort(idx)].tolist()
>>>['c','b','a']

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.


Isso converterá a lista em um array numpy, que é uma bagunça e não funciona para strings.
precisa saber é o seguinte

1
@ user227666 obrigado por sua opinião, mas isso não é verdade ele funciona mesmo com a corda e você pode adicionar .ToList se você deseja obter uma lista ...
GM

1
Eu acho que é como tentar matar uma abelha com uma marreta. Funciona, com certeza! Mas importar uma biblioteca para esse fim pode ser um pouco exagerado, não é?
Debosmit Ray

@DebosmitRay, poderia ser útil se você trabalha na Data Science, onde normalmente trabalha com numpy e muitas vezes precisa trabalhar com array numpy.
GM

a melhor resposta em 2020 @DebosmitRay Espero que você mude de idéia e use numpy / pandas sempre que puder
Egos

21

Outra maneira de fazer:

>>> seq = [1,2,3,'a', 'a', 1,2]
>> dict.fromkeys(seq).keys()
['a', 1, 2, 3]

1
Observe que nas versões modernas do Python (2.7+, mas não me lembro com certeza), keys()retorna um objeto de exibição de dicionário, não uma lista.
Dustin Wyatt

16

Simples e fácil:

myList = [1, 2, 3, 1, 2, 5, 6, 7, 8]
cleanlist = []
[cleanlist.append(x) for x in myList if x not in cleanlist]

Resultado:

>>> cleanlist 
[1, 2, 3, 5, 6, 7, 8]

5
complexidade quadrática, no entanto - iné O funcionamento (n) e seu cleanlistvai ter no máximo nnúmeros => pior caso ~ O (n ^ 2)
jermenkoo

6
a compreensão da lista não deve ser usada para efeitos colaterais.
Jean-François Fabre

13

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))if my_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:

from collections import OrderedDict, Counter

class Container:
    def __init__(self, obj):
        self.obj = obj
    def __eq__(self, obj):
        return self.obj == obj
    def __hash__(self):
        try:
            return hash(self.obj)
        except:
            return id(self.obj)

class OrderedCounter(Counter, OrderedDict):
     'Counter that remembers the order elements are first encountered'

     def __repr__(self):
         return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))

     def __reduce__(self):
         return self.__class__, (OrderedDict(self),)

def remd(sequence):
    cnt = Counter()
    for x in sequence:
        cnt[Container(x)] += 1
    return [item.obj for item in cnt]

def oremd(sequence):
    cnt = OrderedCounter()
    for x in sequence:
        cnt[Container(x)] += 1
    return [item.obj for item in cnt]

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

insira a descrição da imagem aqui (Mais zoom) insira a descrição da imagem aqui

Hashables ordenados

insira a descrição da imagem aqui (Mais zoom) insira a descrição da imagem aqui

Encomendado Unhashables

insira a descrição da imagem aqui (Mais zoom) insira a descrição da imagem aqui


11

Eu tinha um ditado na minha lista, então não pude usar a abordagem acima. Eu recebi o erro:

TypeError: unhashable type:

Então, se você se importa com a ordem e / ou alguns itens são laváveis . Então você pode achar isso útil:

def make_unique(original_list):
    unique_list = []
    [unique_list.append(obj) for obj in original_list if obj not in unique_list]
    return unique_list

Alguns podem considerar a compreensão da lista com um efeito colateral não uma boa solução. Aqui está uma alternativa:

def make_unique(original_list):
    unique_list = []
    map(lambda x: unique_list.append(x) if (x not in unique_list) else False, original_list)
    return unique_list

6
mapcom 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 passar unique_list.append.
abarnert

Maneira muito útil de acrescentar elementos em apenas uma linha, obrigado!
ZLNK

2
@ZLNK, por favor, nunca use isso. Além de ser conceitualmente feio, também é extremamente ineficiente, porque na verdade você cria uma lista potencialmente grande e a joga fora apenas para executar a iteração básica.
Eli Korvigo 13/03/19

10

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+ listlimitadas a entradas hasháveis. Aqui está uma solução O (nlogn) independente de hash:

A atualização adicionou o keyargumento, a documentação e a compatibilidade com o Python 3.

# from functools import reduce <-- add this import on Python 3

def uniq(iterable, key=lambda x: x):
    """
    Remove duplicates from an iterable. Preserves order. 
    :type iterable: Iterable[Ord => A]
    :param iterable: an iterable of objects of any orderable type
    :type key: Callable[A] -> (Ord => B)
    :param key: optional argument; by default an item (A) is discarded 
    if another item (B), such that A == B, has already been encountered and taken. 
    If you provide a key, this condition changes to key(A) == key(B); the callable 
    must return orderable objects.
    """
    # Enumerate the list to restore order lately; reduce the sorted list; restore order
    def append_unique(acc, item):
        return acc if key(acc[-1][1]) == key(item[1]) else acc.append(item) or acc 
    srt_enum = sorted(enumerate(iterable), key=lambda item: key(item[1]))
    return [item[1] for item in sorted(reduce(append_unique, srt_enum, [srt_enum[0]]))] 

No entanto, esta solução requer elementos ordenáveis. Vou usá-lo para unificar minha lista de listas: é muito difícil listar 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.
Loxaxs

Penso que a abordagem baseada em conjuntos é igualmente barata (O (n log n)), ou mais barata, do que a classificação + detecção de únicos. (Essa abordagem seria muito melhor, porém.) Também não preserva exatamente a ordem inicial, mas fornece uma ordem previsível.
9000

@ 9000 Isso é verdade. Eu nunca mencionei a complexidade de tempo de uma abordagem baseada em tabela de hash, que é obviamente O (n). Aqui você pode encontrar muitas respostas incorporando tabelas de hash. Porém, eles não são universais porque exigem que os objetos sejam laváveis. Além disso, eles consomem muito mais memória.
Eli Korvigo 06/06

Leva tempo para ler e entender esta resposta. Existe um ponto em enumerar quando você não está usando os índices? O reduce() já está trabalhando em uma coleção classificada srt_enum, por que você se inscreveu sortednovamente?
Brayoni

@Brayoni o primeiro tipo existe para agrupar valores iguais, o segundo tipo existe para restaurar a ordem inicial. A enumeração é necessária para acompanhar a ordem relativa original.
Eli Korvigo

9

Se você deseja preservar o pedido e não usar nenhum módulo externo, aqui está uma maneira fácil de fazer isso:

>>> t = [1, 9, 2, 3, 4, 5, 3, 6, 7, 5, 8, 9]
>>> list(dict.fromkeys(t))
[1, 9, 2, 3, 4, 5, 6, 7, 8]

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

from collections import OrderedDict
ulist=list(OrderedDict.fromkeys(l))

mas é muito mais curto e corre mais rápido.

Isso funciona porque cada vez que a fromkeysfunção tenta criar uma nova chave, se o valor já existir, ela simplesmente a substituirá. No entanto, isso não afeta o dicionário, pois fromkeyscria um dicionário em que todas as chaves têm o valor None; portanto, efetivamente elimina todas as duplicatas dessa maneira.


Também experimente aqui
vineeshvs

8

Você também pode fazer isso:

>>> t = [1, 2, 3, 3, 2, 4, 5, 6]
>>> s = [x for i, x in enumerate(t) if i == t.index(x)]
>>> s
[1, 2, 3, 4, 5, 6]

A razão que funciona acima é que o indexmétodo retorna apenas o primeiro índice de um elemento. Elementos duplicados têm índices mais altos. Consulte aqui :

list.index (x [, start [, end]])
Retorna o índice baseado em zero na lista do primeiro item cujo valor é x. Gera um ValueError se não houver esse item.


Isso é terrivelmente ineficiente. list.indexé uma operação de tempo linear, tornando sua solução quadrática.
Eli Korvigo 13/04/19

Você está certo. Mas também acredito que é bastante óbvio que a solução pretende ser uma linha que preserva a ordem. Todo o resto já está aqui.
Atonal 13/10

7

Tente usar conjuntos:

import sets
t = sets.Set(['a', 'b', 'c', 'd'])
t1 = sets.Set(['a', 'b', 'c'])

print t | t1
print t - t1

7

Reduza a variante com a reserva de pedidos:

Suponha que tenhamos uma lista:

l = [5, 6, 6, 1, 1, 2, 2, 3, 4]

Reduzir variante (ineficiente):

>>> reduce(lambda r, v: v in r and r or r + [v], l, [])
[5, 6, 1, 2, 3, 4]

5x mais rápido, mas mais sofisticado

>>> reduce(lambda r, v: v in r[1] and r or (r[0].append(v) or r[1].add(v)) or r, l, ([], set()))[0]
[5, 6, 1, 2, 3, 4]

Explicação:

default = (list(), set())
# user list to keep order
# use set to make lookup faster

def reducer(result, item):
    if item not in result[1]:
        result[0].append(item)
        result[1].add(item)
    return result

reduce(reducer, l, default)[0]

7

A melhor abordagem para remover duplicatas de uma lista é usar a função set () , disponível em python, convertendo novamente esse conjunto em lista

In [2]: some_list = ['a','a','v','v','v','c','c','d']
In [3]: list(set(some_list))
Out[3]: ['a', 'c', 'd', 'v']

@MeetZaveri glad.!
Anurag Misra

Instanciar novas listas e conjuntos não é gratuito. O que acontece se fizermos isso várias vezes em rápida sucessão (ou seja, em um loop muito restrito) e as listas forem muito pequenas?
Z4-camada nível

6

Você pode usar a seguinte função:

def rem_dupes(dup_list): 
    yooneeks = [] 
    for elem in dup_list: 
        if elem not in yooneeks: 
            yooneeks.append(elem) 
    return yooneeks

Exemplo :

my_list = ['this','is','a','list','with','dupicates','in', 'the', 'list']

Uso:

rem_dupes(my_list)

['this', 'is', 'a', 'list', 'with', 'dupicates', 'in', 'o']


5

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:

def uniqify(iterable):
    seen = set()
    for item in iterable:
        if item not in seen:
            seen.add(item)
            yield item

Isso retorna um gerador / iterador, para que você possa usá-lo em qualquer lugar que possa usar um iterador.

for unique_item in uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]):
    print(unique_item, end=' ')

print()

Resultado:

1 2 3 4 5 6 7 8

Se você deseja um list, pode fazer o seguinte:

unique_list = list(uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]))

print(unique_list)

Resultado:

[1, 2, 3, 4, 5, 6, 7, 8]

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.)
dylnmc

2
@dylnmc, é uma operação em lote e também perde a ordem. Minha resposta foi especificamente planejada para ser rápida e em ordem de primeira ocorrência. :)
Cyphase

5

Sem usar set

data=[1, 2, 3, 1, 2, 5, 6, 7, 8]
uni_data=[]
for dat in data:
    if dat not in uni_data:
        uni_data.append(dat)

print(uni_data) 

5

Você pode usar setpara remover duplicatas:

mylist = list(set(mylist))

Mas observe que os resultados serão desordenados. Se isso é um problema:

mylist.sort()

1
Você pode simplesmente fazer: mylist = ordenado (list (set (mylist))))
Erik Campobadal

5

Mais uma abordagem melhor poderia ser,

import pandas as pd

myList = [1, 2, 3, 1, 2, 5, 6, 7, 8]
cleanList = pd.Series(myList).drop_duplicates().tolist()
print(cleanList)

#> [1, 2, 3, 5, 6, 7, 8]

e a ordem permanece preservada.


Embora isso possa funcionar bem, o uso de uma biblioteca pesada como pandas para esse fim parece um exagero.
Glutexo 20/03/19

4

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:

def remove_duplicates(list):
    ''' Removes duplicate items from a list '''
    singles_list = []
    for element in list:
        if element not in singles_list:
            singles_list.append(element)
    return singles_list

1. Você nunca deve ocultar nomes incorporados (pelo menos, tão importantes quanto list); 2. Seu método é extremamente ruim: é quadrático no número de elementos em list.
Eli Korvigo 07/01

1. Correto, mas este foi um exemplo; 2. Correto, e essa é exatamente a razão pela qual eu ofereci. Todas as soluções postadas aqui têm prós e contras. Alguns sacrificam simplicidade ou ordem, os meus sacrificam escalabilidade.
Cgf 20/0318

este é um algoritmo de "Shlemiel, o pintor" ...
Z4-camada

4

o código abaixo é simples para remover duplicados na lista

def remove_duplicates(x):
    a = []
    for i in x:
        if i not in a:
            a.append(i)
    return a

print remove_duplicates([1,2,2,3,3,4])

retorna [1,2,3,4]


2
Se você não se importa com o pedido, isso leva muito mais tempo. 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!
dylnmc 23/09/16

@dylnmc isso também é uma duplicata de um significativamente mais velhos resposta
Eli Korvigo

4

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 retorna Nonecomo resultado, que é avaliado como False, portanto, o lado direito de orsempre seria o resultado dessa expressão.

Time it yourself

def deduplicate(sequence):
    visited = set()
    adder = visited.add  # get rid of qualification overhead
    out = [adder(item) or item for item in sequence if item not in visited]
    return out

4

Usando o conjunto :

a = [0,1,2,3,4,3,3,4]
a = list(set(a))
print a

Usando exclusivo :

import numpy as np
a = [0,1,2,3,4,3,3,4]
a = np.unique(a).tolist()
print a

4

Infelizmente. A maioria das respostas aqui não preserva o pedido ou é muito longa. Aqui está uma resposta simples e preservadora de pedidos.

s = [1,2,3,4,5,2,5,6,7,1,3,9,3,5]
x=[]

[x.append(i) for i in s if i not in x]
print(x)

Isso fornecerá x com duplicatas removidas, mas preservando o pedido.


3

Maneira muito simples em Python 3:

>>> n = [1, 2, 3, 4, 1, 1]
>>> n
[1, 2, 3, 4, 1, 1]
>>> m = sorted(list(set(n)))
>>> m
[1, 2, 3, 4]

2
sorted(list(...))é redundante ( sortedjá converte implicitamente seu argumento em um novo list, classifica-o e depois retorna o novo list, portanto, usando os dois meios, torna temporário desnecessário list). Use apenas listse o resultado não precisar ser classificado, use apenas sortedse o resultado precisar ser classificado.
precisa

3

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

line = [1, 2, 3, 1, 2, 5, 6, 7, 8]
new_line = sorted(set(line), key=line.index) # remove duplicated element
print(new_line)

Você obterá o resultado

[1, 2, 3, 5, 6, 7, 8]

Método 2: caso especial

TypeError: unhashable type: 'list'

O caso especial para processar unhashable ( 3 códigos de linha )

line=[['16.4966155686595', '-27.59776154691', '52.3786295521147']
,['16.4966155686595', '-27.59776154691', '52.3786295521147']
,['17.6508629295574', '-27.143305738671', '47.534955022564']
,['17.6508629295574', '-27.143305738671', '47.534955022564']
,['18.8051102904552', '-26.688849930432', '42.6912804930134']
,['18.8051102904552', '-26.688849930432', '42.6912804930134']
,['19.5504702331098', '-26.205884452727', '37.7709192714727']
,['19.5504702331098', '-26.205884452727', '37.7709192714727']
,['20.2929416861422', '-25.722717575124', '32.8500163147157']
,['20.2929416861422', '-25.722717575124', '32.8500163147157']]

tuple_line = [tuple(pt) for pt in line] # convert list of list into list of tuple
tuple_new_line = sorted(set(tuple_line),key=tuple_line.index) # remove duplicated element
new_line = [list(t) for t in tuple_new_line] # convert list of tuple into list of list

print (new_line)

Você obterá o resultado:

[
  ['16.4966155686595', '-27.59776154691', '52.3786295521147'], 
  ['17.6508629295574', '-27.143305738671', '47.534955022564'], 
  ['18.8051102904552', '-26.688849930432', '42.6912804930134'], 
  ['19.5504702331098', '-26.205884452727', '37.7709192714727'], 
  ['20.2929416861422', '-25.722717575124', '32.8500163147157']
]

Como a tupla é lavável e você pode converter dados entre lista e tupla facilmente

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.