Eliminar duplicados en listas


998

Bastante necesito escribir un programa para verificar si una lista tiene duplicados y si lo hace los elimina y devuelve una nueva lista con los elementos que no fueron duplicados / eliminados. Esto es lo que tengo, pero para ser honesto, no sé qué hacer.

def remove_duplicates():
    t = ['a', 'b', 'c', 'd']
    t2 = ['a', 'c', 'd']
    for t in t2:
        t.append(t.remove())
    return t

22
Su descripción dice que verifica "una lista" en busca de duplicados, pero su código verifica dos listas.
Brendan Long


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

Respuestas:


1643

El enfoque común para obtener una colección única de artículos es usar a set. Los conjuntos son colecciones desordenadas de objetos distintos . Para crear un conjunto desde cualquier iterable, simplemente puede pasarlo a la set()función incorporada. Si más tarde necesita una lista real nuevamente, puede pasar el conjunto de manera similar a la list()función.

El siguiente ejemplo debería cubrir todo lo que intente hacer:

>>> 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 puede ver en el resultado del ejemplo, el orden original no se mantiene . Como se mencionó anteriormente, los conjuntos en sí mismos son colecciones desordenadas, por lo que se pierde el orden. Al convertir un conjunto a una lista, se crea un orden arbitrario.

Orden de mantenimiento

Si el orden es importante para usted, deberá utilizar un mecanismo diferente. Una solución muy común para esto es confiar en OrderedDictmantener el orden de las claves durante la inserción:

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

Comenzando con Python 3.7 , el diccionario incorporado también garantiza el orden de inserción, por lo que también puede usarlo directamente si está en Python 3.7 o posterior (o CPython 3.6):

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

Tenga en cuenta que esto puede tener cierta sobrecarga de crear un diccionario primero y luego crear una lista a partir de él. Si en realidad no necesita preservar el orden, a menudo es mejor usar un conjunto, especialmente porque le brinda muchas más operaciones para trabajar. Consulte esta pregunta para obtener más detalles y formas alternativas de preservar el pedido al eliminar duplicados.


Finalmente, tenga en cuenta que tanto las soluciones setcomo las OrderedDict/ dictrequieren que sus elementos sean hashaable . Esto generalmente significa que tienen que ser inmutables. Si tiene que lidiar con elementos que no se pueden compartir (p. Ej., Objetos de lista), tendrá que usar un enfoque lento en el que básicamente tendrá que comparar cada elemento con todos los demás elementos en un bucle anidado.


44
Esto no funciona para elementos de lista no compartibles (por ejemplo, una lista de listas)
KNejad

3
@KNejad Eso es lo que dice el último párrafo.
meter el

Oh vaya. Debería haber leído todo. Lo que terminé haciendo fue usar tuplas en lugar de listas, por lo que este enfoque aún podría funcionar.
KNejad

agregue esto al ejemplo, t = [3, 2, 1, 1, 2, 5, 6, 7, 8], ¡muestra la diferencia claramente!
sailfish009

"... sobrecarga de crear un diccionario primero ... Si realmente no necesita preservar el orden, es mejor que use un conjunto". - Perfilé esto porque tenía curiosidad por saber si era realmente cierto. Mis tiempos muestran que, de hecho, el conjunto es ligeramente más rápido: 1.12 µs por ciclo (conjunto) frente a 1.53 µs por ciclo (dict) sobre bucles de 1M con una diferencia de tiempo absoluta de aproximadamente 4s sobre iteraciones de 1M. Entonces, si está haciendo esto en un estrecho circuito interno, puede que le importe, de lo contrario, probablemente no.
millerdev

414

En Python 2.7 , la nueva forma de eliminar duplicados de un iterable mientras se mantiene en el orden original es:

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

En Python 3.5 , el OrderedDict tiene una implementación en C. Mis tiempos muestran que este es ahora el más rápido y el más corto de los diversos enfoques para Python 3.5.

En Python 3.6 , el dict regular se hizo ordenado y compacto. (Esta característica es válida para CPython y PyPy pero puede no estar presente en otras implementaciones). Eso nos da una nueva forma más rápida de deducir mientras se conserva el orden:

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

En Python 3.7 , el dict regular está garantizado para ambos ordenados en todas las implementaciones. Entonces, la solución más corta y rápida es:

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

10
Creo que esta es la única forma de mantener los artículos en orden.
Herberth Amaral


55
@MartijnPieters Corrección: creo que esta es la única forma sencilla de mantener los artículos en orden.
Herberth Amaral

12
Para esto también, el contenido de la lista original debe ser hashaable
Davide

Como @Davide mencionó, la lista original debe ser hashaable. Esto significa que esto no funciona para una lista de diccionarios. TypeError: unhashable type: 'dictlist'
CraZ

187

Es una frase: list(set(source_list))hará el truco.

A setes algo que no puede tener duplicados.

Actualización: un enfoque de preservación de pedidos consta de dos líneas:

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

Aquí usamos el hecho de que OrderedDictrecuerda el orden de inserción de las claves, y no lo cambia cuando se actualiza un valor en una clave particular. Insertamos Truecomo valores, pero podríamos insertar cualquier cosa, los valores simplemente no se usan. ( setfunciona muy parecido a un dictcon valores ignorados, también.)


55
Esto solo funciona si source_listes hashable.
Adrian Keister

@AdrianKeister: Esto es cierto. Hay objetos que tienen una semántica de igualdad razonable pero que no se pueden compartir, por ejemplo, listas. OTOH si no podemos tener un atajo como un hastable, terminamos con un algoritmo cuadrático de solo comparar cada elemento con todos los elementos únicos conocidos actualmente. Esto puede ser totalmente correcto para entradas cortas, especialmente con muchos duplicados.
9000

Correcto, exactamente. Creo que su respuesta sería de mayor calidad si tuviera en cuenta este caso de uso muy común.
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
Tenga en cuenta que este método funciona en tiempo O (n ^ 2) y, por lo tanto, es muy lento en listas grandes.
dotancohen

@Chris_Rands: no estoy seguro de que frozensetfuncione con contenido no hashable. Todavía recibo el error no hashable cuando lo uso frozenset.
Adrian Keister el

85

Si no te importa el pedido, solo haz esto:

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

Se setgarantiza que A no tiene duplicados.


3
No funciona a menos que lsea ​​hashable.
Adrian Keister el

41

Para hacer una nueva lista conservando el orden de los primeros elementos de duplicados en L

newlist=[ii for n,ii in enumerate(L) if ii not in L[:n]]

por ejemplo if L=[1, 2, 2, 3, 4, 2, 4, 3, 5]entonces newlistserá[1,2,3,4,5]

Esto verifica que cada elemento nuevo no haya aparecido previamente en la lista antes de agregarlo. Además no necesita importaciones.


3
Esto tiene una complejidad temporal de O (n ^ 2) . Las respuestas con sety OrderedDictpueden tener menor complejidad de tiempo amortizado.
blubberdiblub

Utilicé esta solución en mi código y funcionó muy bien, pero creo que lleva mucho tiempo
Gerasimos Ragavanis

@blubberdiblub, ¿puede explicar qué mecanismo más eficiente para el código existe en set y OrderedDict que podría hacer que sean menos lentos? (excluyendo los gastos generales de cargarlos)
ilias iliadis

@iliasiliadis Las implementaciones habituales de set y dict usan hashes o (alguna forma de árboles balanceados). Debe considerar construir el conjunto o dict y buscar en él (varias veces), pero su complejidad amortizada generalmente es aún menor que O (n ^ 2) . "Amortizado" en términos simples significa en promedio (pueden tener los peores casos con mayor complejidad que el caso promedio). Esto solo es relevante cuando tienes una gran cantidad de artículos.
blubberdiblub

25

Un colega me envió la respuesta aceptada como parte de su código para una revisión de código hoy. Aunque ciertamente admiro la elegancia de la respuesta en cuestión, no estoy contento con el rendimiento. He probado esta solución (uso set para reducir el tiempo de búsqueda)

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 la eficiencia, utilicé una muestra aleatoria de 100 enteros: 62 eran únicos

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

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

Aquí están los resultados de las mediciones.

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

Bueno, ¿qué sucede si se elimina el conjunto de la solución?

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

El resultado no es tan malo como con el OrderedDict , pero sigue siendo más de 3 veces la solución original.

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

Agradable usar la búsqueda rápida establecida para acelerar la comparación en bucle. Si el orden no importa, la lista (set (x)) sigue siendo 6 veces más rápido que esto
Joop

@Joop, esa fue mi primera pregunta para mi colega: el orden sí importa; de lo contrario, habría sido un problema trivial
volcán

versión optimizada del conjunto ordenado, para cualquier persona interesada 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

25

También hay soluciones con Pandas y Numpy. Ambos devuelven una matriz numpy, por lo que debe usar la función .tolist()si desea una lista.

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

Solución de pandas

Usando la función Pandas unique():

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

Solución de Numpy

Usando la función numpy unique().

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

Tenga en cuenta que numpy.unique () también ordena los valores . Entonces la lista t2se devuelve ordenada. Si desea conservar el orden, use como en esta respuesta :

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

La solución no es tan elegante en comparación con las otras, sin embargo, en comparación con pandas.unique (), numpy.unique () también le permite verificar si las matrices anidadas son únicas a lo largo de un eje seleccionado.


Esto convertirá la lista en una matriz numpy que es un desastre y no funcionará para las cadenas.
user227666

1
@ user227666 gracias por su revisión, pero eso no es cierto, funciona incluso con cadenas y puede agregar .tolist si desea obtener una lista ...
GM

1
Creo que esto es como intentar matar una abeja con un mazo. Funciona, claro! Pero, importar una biblioteca solo para este propósito puede ser un poco exagerado, ¿no?
Debosmit Ray

@DebosmitRay podría ser útil si trabaja en Data Science donde generalmente trabaja con numpy y muchas veces necesita trabajar con numpy array.
GM

la mejor respuesta en 2020 @DebosmitRay, espero que cambies de opinión y uses pandas / numpy cada vez que puedas
Egos

21

Otra forma de hacer:

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

1
Tenga en cuenta que en las versiones modernas de Python (2.7+ creo, pero no lo recuerdo con certeza), keys()devuelve un objeto de vista de diccionario, no una lista.
Dustin Wyatt

16

Simple y 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]

Salida:

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

55
sin embargo, la complejidad cuadrática - ines operación O (n) y cleanlisttendrá como máximo nnúmeros => peor de los casos ~ O (n ^ 2)
jermenkoo

66
las comprensiones de la lista no deben usarse para los efectos secundarios.
Jean-François Fabre

13

En esta respuesta, habrá dos secciones: dos soluciones únicas y un gráfico de velocidad para soluciones específicas.

Eliminar elementos duplicados

La mayoría de estas respuestas solo eliminan los elementos duplicados que son hashables , pero esta pregunta no implica que no solo necesite elementos hashable , lo que significa que ofreceré algunas soluciones que no requieren elementos hashaable .

colecciones.Counter es una herramienta poderosa en la biblioteca estándar que podría ser perfecta para esto. Solo hay otra solución que incluso tiene Counter. Sin embargo, esa solución también se limita a las claves hashaable .

Para permitir claves no compartibles en Counter, hice una clase Container, que intentará obtener la función hash predeterminada del objeto, pero si falla, probará su función de identidad. También define una ecuación y un método hash . Esto debería ser suficiente para permitir elementos no compartibles en nuestra solución. Los objetos no compartibles serán tratados como si fueran hashables. Sin embargo, esta función hash usa identidad para objetos no compartibles, lo que significa que dos objetos iguales que son ambos no compartibles no funcionarán. Le sugiero que anule esto y lo cambie para usar el hash de un tipo mutable equivalente (como usar hash(tuple(my_list))if my_listes una lista).

También hice dos soluciones. Otra solución que mantiene el orden de los elementos, usando una subclase de OrderedDict y Counter que se llama 'OrderedCounter'. Ahora, aquí están las funciones:

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 es una ordenación no ordenada, oremd es una ordenación ordenada. Puedes decir claramente cuál es más rápido, pero te lo explicaré de todos modos. La ordenación no ordenada es un poco más rápida. Mantiene menos datos, ya que no necesita orden.

Ahora, también quería mostrar las comparaciones de velocidad de cada respuesta. Entonces, lo haré ahora.

¿Qué función es la más rápida?

Para eliminar duplicados, reuní 10 funciones de algunas respuestas. Calculé la velocidad de cada función y la puse en un gráfico usando matplotlib.pyplot .

Dividí esto en tres rondas de gráficos. Un hashable es cualquier objeto que puede ser hash, un no hashable es cualquier objeto que no puede ser hash. Una secuencia ordenada es una secuencia que conserva el orden, una secuencia desordenada no conserva el orden. Ahora, aquí hay algunos términos más:

Hashable desordenado era para cualquier método que eliminara duplicados, que no necesariamente tenía que mantener el orden. No tenía que funcionar para los incontrolables, pero podía.

Hashable ordenado era para cualquier método que mantuviera el orden de los elementos en la lista, pero no tenía que funcionar para los no compartibles, pero podía.

Ordenado no compartible era cualquier método que mantenía el orden de los elementos de la lista y funcionaba para los no compartibles.

En el eje y es la cantidad de segundos que tardó.

En el eje x es el número al que se aplicó la función.

Generamos secuencias para hashables no ordenados y hashables ordenados con la siguiente comprensión: [list(range(x)) + list(range(x)) for x in range(0, 1000, 10)]

Para los no compartidos ordenados: [[list(range(y)) + list(range(y)) for y in range(x)] for x in range(0, 1000, 10)]

Tenga en cuenta que hay un 'paso' en el rango porque sin él, esto hubiera tardado 10 veces más. También porque, en mi opinión personal, pensé que podría haber sido un poco más fácil de leer.

También tenga en cuenta que las teclas de la leyenda son lo que traté de adivinar como las partes más vitales de la función. ¿En cuanto a qué función hace lo peor o lo mejor? El gráfico habla por sí mismo.

Con eso resuelto, aquí están los gráficos.

Hashables desordenados

ingrese la descripción de la imagen aquí (Aumentado) ingrese la descripción de la imagen aquí

Hashables ordenados

ingrese la descripción de la imagen aquí (Aumentado) ingrese la descripción de la imagen aquí

Ordenadas inquebrantables

ingrese la descripción de la imagen aquí (Aumentado) ingrese la descripción de la imagen aquí


11

Tenía un dict en mi lista, por lo que no podía usar el enfoque anterior. Recibí el error:

TypeError: unhashable type:

Entonces, si le importa el orden y / o algunos artículos son inquebrantables . Entonces te puede resultar ú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

Algunos pueden considerar que la comprensión de listas con un efecto secundario no es una buena solución. Aquí hay una 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

66
mapcon un efecto secundario es aún más engañoso que una lista con un efecto secundario. Además, lambda x: unique_list.append(x)es solo una forma más lenta y lenta de pasar unique_list.append.
abarnert

Forma muy útil de agregar elementos en una sola línea, ¡gracias!
ZLNK

2
@ZLNK por favor, nunca uses eso. Además de ser conceptualmente feo, también es extremadamente ineficiente, porque en realidad crea una lista potencialmente grande y la descarta solo para realizar una iteración básica.
Eli Korvigo

10

Todos los enfoques de preservación del orden que he visto aquí hasta ahora usan una comparación ingenua (con O (n ^ 2) complejidad de tiempo en el mejor de los casos) o combinaciones de peso pesado OrderedDicts/ set+ listque se limitan a entradas hashaable. Aquí hay una solución O (nlogn) independiente de hash:

La actualización agregó el keyargumento, la documentación y la compatibilidad con 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]]))] 

Sin embargo, esta solución requiere elementos ordenables. Lo usaré para uniquificar mi lista de listas: es una molestia hacer tuple()listas y hacerlas hash. El | El | El | El | - En términos generales, el proceso de hash tarda un tiempo proporcional al tamaño de los datos completos, mientras que esta solución lleva un tiempo O (nlog (n)), dependiendo solo de la longitud de la lista.
loxaxs

Creo que el enfoque basado en conjuntos es igualmente barato (O (n log n)), o más barato, que la clasificación + detección de elementos únicos. (Sin embargo, este enfoque sería mucho más paralelo). Tampoco conserva exactamente el orden inicial, pero da un orden predecible.
9000

@ 9000 Eso es cierto. Nunca he mencionado la complejidad temporal de un enfoque basado en tablas hash, que obviamente es O (n). Aquí puede encontrar muchas respuestas que incorporan tablas hash. Sin embargo, no son universales porque requieren que los objetos sean hashable. Además, requieren mucha más memoria.
Eli Korvigo

Toma tiempo leer y comprender esta respuesta. ¿Hay algún punto en enumerar cuando no está utilizando los índices? El reduce() ya está trabajando en una colección ordenada srt_enum, ¿por qué solicitó sortednuevamente?
Brayoni

@Brayoni, el primer tipo está allí para agrupar valores iguales, el segundo tipo está allí para restaurar el orden inicial. La enumeración es necesaria para realizar un seguimiento del orden relativo original.
Eli Korvigo

9

Si desea preservar el pedido y no utilizar ningún módulo externo, esta es una manera fácil de hacerlo:

>>> 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 conserva el orden de aparición, por lo que, como se vio anteriormente, vendrán nueve después de uno porque fue la primera vez que apareció. Sin embargo, este es el mismo resultado que obtendrías haciendo

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

pero es mucho más corto y corre más rápido.

Esto funciona porque cada vez que la fromkeysfunción intenta crear una nueva clave, si el valor ya existe, simplemente lo sobrescribirá. Sin embargo, esto no afectará en absoluto al diccionario, ya que fromkeyscrea un diccionario donde todas las claves tienen el valor None, por lo que efectivamente elimina todos los duplicados de esta manera.


También pruébalo aquí
vineeshvs

8

También puedes hacer esto:

>>> 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]

La razón por la que funciona anteriormente es que ese indexmétodo devuelve solo el primer índice de un elemento. Los elementos duplicados tienen índices más altos. Consulte aquí :

list.index (x [, start [, end]])
Devuelve un índice basado en cero en la lista del primer elemento cuyo valor es x. Provoca un ValueError si no existe dicho elemento.


Esto es terriblemente ineficiente. list.indexes una operación de tiempo lineal, lo que hace que su solución sea cuadrática.
Eli Korvigo

Tienes razón. Pero también creo que es bastante obvio que la solución pretende ser un trazador de líneas que conserve el orden. Todo lo demás ya está aquí.
Atonal

7

Intenta usar conjuntos:

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

print t | t1
print t - t1

7

Reduzca la variante con la preservación de pedidos:

Supongamos que tenemos una lista:

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

Reducir variante (ineficiente):

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

5 veces más rápido pero más 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]

Explicación:

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

El mejor enfoque para eliminar duplicados de una lista es usar la función set () , disponible en python, convirtiendo nuevamente ese conjunto en una 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 contento!
Anurag Misra

Crear instancias de nuevas listas y conjuntos no es gratuito. ¿Qué sucede si hacemos esto muchas veces en rápida sucesión (es decir, en un ciclo muy cerrado) y las listas son muy pequeñas?
Z4-tier

6

Puede usar la siguiente función:

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

Ejemplo :

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

Uso:

rem_dupes(my_list)

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


5

Hay muchas otras respuestas que sugieren diferentes formas de hacer esto, pero todas son operaciones por lotes, y algunas de ellas desechan el pedido original. Eso podría estar bien dependiendo de lo que necesite, pero si desea iterar sobre los valores en el orden de la primera instancia de cada valor, y desea eliminar los duplicados sobre la marcha versus todos a la vez, puede usar este generador:

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

Esto devuelve un generador / iterador, por lo que puede usarlo en cualquier lugar donde pueda usar un iterador.

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

print()

Salida:

1 2 3 4 5 6 7 8

Si quieres un list, puedes hacer esto:

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

print(unique_list)

Salida:

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

seen = set(iterable); for item in seen: yield itemEs casi seguro que es más rápido. (No he probado este caso específico, pero esa sería mi suposición.)
dylnmc

2
@dylnmc, esa es una operación por lotes, y también pierde el orden. Mi respuesta estaba destinada específicamente a ser sobre la marcha y en orden de primera aparición. :)
Cyphase

5

Sin 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

Puede usar setpara eliminar duplicados:

mylist = list(set(mylist))

Pero tenga en cuenta que los resultados serán desordenados. Si eso es un problema:

mylist.sort()

1
Simplemente puede hacer: mylist = sorted (list (set (mylist)))
Erik Campobadal

5

Un mejor enfoque más podría 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]

y el orden permanece preservado.


Aunque esto podría funcionar bien, usar una biblioteca pesada como pandas para este propósito parece una exageración.
Glutexo

4

Este se preocupa por el pedido sin demasiados problemas (OrderdDict y otros). Probablemente no sea la forma más pitónica, ni la más corta, pero el truco es:

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. Nunca debe sombrear los nombres incorporados (al menos, tan importante como list); 2. Su método escala extremadamente mal: es cuadrático en el número de elementos en list.
Eli Korvigo el

1. Correcto, pero este fue un ejemplo; 2. Correcto, y esa es exactamente la razón por la que lo ofrecí. Todas las soluciones publicadas aquí tienen pros y contras. Algunos sacrifican la simplicidad o el orden, el mío sacrifica la escalabilidad.
cgf

este es un algoritmo de "Shlemiel el pintor" ...
Z4-tier

4

el siguiente código es simple para eliminar duplicados en la 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])

vuelve [1,2,3,4]


2
Si no le importa el orden, esto lleva mucho más tiempo. list(set(..))(más de 1 millón de pases) superará esta solución en aproximadamente 10 segundos completos, mientras que este enfoque dura aproximadamente 12 segundos, ¡ list(set(..))solo demora aproximadamente 2 segundos!
dylnmc

@dylnmc esto también es un duplicado de una respuesta
Eli Korvigo el

4

Aquí está la solución pitónica más rápida que se presenta a otros que figuran en las respuestas.

El uso de los detalles de implementación de la evaluación de cortocircuito permite utilizar la comprensión de la lista, que es lo suficientemente rápida. visited.add(item)siempre se devuelve Nonecomo resultado, que se evalúa como False, por lo que el lado derecho de orsiempre sería el resultado de dicha expresión.

Míralo tú mismo

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

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

Usando único :

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

4

Desafortunadamente. La mayoría de las respuestas aquí no conservan el orden o son demasiado largas. Aquí hay una respuesta simple para preservar el orden.

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)

Esto le dará x con los duplicados eliminados pero conservando el orden.


3

De manera muy simple en 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(...))es redundante ( sortedya convierte implícitamente su argumento en nuevo list, lo ordena, luego devuelve el nuevo list, por lo que usar ambos significa hacer un temporal innecesario list). Use solo listsi el resultado no necesita ser ordenado, use solo sortedsi el resultado necesita ser ordenado.
ShadowRanger

3

La magia del tipo incorporado de Python

En python, es muy fácil procesar los casos complicados como este y solo por el tipo incorporado de python.

Déjame mostrarte cómo hacerlo!

Método 1: caso general

La forma ( código de 1 línea ) para eliminar elementos duplicados en la lista y seguir ordenando

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

Obtendrás el resultado

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

Método 2: caso especial

TypeError: unhashable type: 'list'

El caso especial para procesar no compartible ( códigos de 3 líneas )

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)

Obtendrás el 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']
]

Debido a que la tupla es hashable y puedes convertir datos entre la lista y la tupla fácilmente

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.