Eliminar duplicados en listas

Más o menos necesito escribir un progtwig para verificar si una lista tiene duplicados y si los elimina, devuelve una nueva lista con los elementos que no se duplicaron / eliminaron. 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 

El enfoque común para obtener una colección única de artículos es utilizar un set . Los conjuntos son colecciones desordenadas de objetos distintos . Para crear un conjunto a partir de cualquier iterable, simplemente puede pasarlo a la función integrada set() . Si luego vuelve a necesitar una lista real, también puede pasar el conjunto a la función list() .

El siguiente ejemplo debería abarcar lo que esté tratando de 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 pedido original no se mantiene. Como se mencionó anteriormente, los conjuntos en sí mismos son colecciones no ordenadas, por lo que el orden se pierde. Al convertir un conjunto de nuevo a una lista, se crea un orden arbitrario.

Si el orden es importante para usted, entonces tendrá que usar un mecanismo diferente. Una solución muy común para esto es confiar en OrderedDict para mantener el orden de las claves durante la inserción:

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

Tenga en cuenta que esto tiene la sobrecarga de crear un diccionario primero, y luego crear una lista a partir de él. Entonces, si realmente no necesitas conservar el orden, es mejor que uses un juego. Echa un vistazo a esta pregunta para obtener más detalles y formas alternativas de conservar el orden al eliminar duplicados.


Finalmente, tenga en cuenta que tanto el set como la solución OrderedDict requieren que sus elementos sean hashable . Esto generalmente significa que tienen que ser inmutables. Si tiene que lidiar con elementos que no son hashable (por ejemplo, enumerar objetos), entonces tendrá que usar un enfoque lento en el que básicamente tendrá que comparar cada elemento con cada otro elemento en un bucle nested.

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 , 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 volvió ordenado y compacto. (Esta función 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 dedupir y retener el orden:

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

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

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

Es de una sola línea: list(set(source_list)) hará el truco.

Un set es algo que no puede tener duplicados.

Actualización: un enfoque de preservación de orden es de dos líneas:

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

Aquí utilizamos el hecho de que OrderedDict recuerda el orden de inserción de las claves, y no lo cambia cuando se actualiza un valor en una clave en particular. Insertamos True como valores, pero podríamos insertar cualquier cosa, los valores simplemente no se utilizan. ( set funciona como un dict con valores ignorados).

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

Si no te importa el pedido, haz esto:

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

Se garantiza que un set no tiene duplicados.

Para hacer una nueva lista reteniendo 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 newlist será [1,2,3,4,5]

Esto comprueba que cada elemento nuevo no haya aparecido previamente en la lista antes de agregarlo. Tampoco necesita importaciones.

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é pasa si el conjunto se elimina 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 OrderedDict , pero aún más de 3 veces de la solución original

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

Otra forma de hacer:

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

También hay soluciones utilizando Pandas y Numpy. Ambos devuelven una matriz numpy, así que tienes que usar la función .tolist() si quieres 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 de 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 . Así que la lista t2 se devuelve ordenada. Si desea conservar el orden, úselo como en esta respuesta :

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

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

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] 

Tenía un dictado en mi lista, por lo que no podía usar el enfoque anterior. Me salió el error

 TypeError: unhashable type: 

Así que si te importa el orden y / o algunos artículos son inestables . Entonces podrías encontrar esto ú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 la comprensión de la lista con un efecto secundario para no ser 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 

Trate de usar conjuntos:

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

También podrías 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 el método de index solo devuelve el primer índice de un elemento. Los elementos duplicados tienen índices más altos. Consulte aquí :

list.index (x [, start [, end]])
Devuelve el índice de base cero en la lista del primer elemento cuyo valor es x. Genera un ValueError si no hay tal elemento.

Todos los enfoques para preservar el orden que he visto hasta ahora utilizan una comparación ingenua (con O (n ^ 2) complejidad de tiempo en el mejor de los casos) o combinaciones de list OrderedDicts / set OrderedDicts gran peso que se limitan a entradas de hashable. Aquí hay una solución O (nlogn) independiente de hash:

Actualización agregó el argumento key , 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 restre order lately; reduce the sorted list; restre 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]]))] 

Reducir variante con preservar de orden:

Supongamos que tenemos 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] 

El mejor método para eliminar duplicados de una lista es usar la función set () , disponible en Python, que convierte de nuevo ese conjunto en 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'] 

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) 

Puede utilizar 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’]

A este le importa el pedido sin demasiados problemas (OrderdDict y otros). Probablemente no sea la forma más pythonica, ni la más corta, pero tiene el truco:

 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 

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

devuelve [1,2,3,4]

Hay muchas otras respuestas que sugieren diferentes maneras 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 en lugar de 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 que 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 una 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] 

Un mejor enfoque 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 se conserva.

Aquí está la solución pythonic más rápida comparada con otras personas que figuran en las respuestas.

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

Tiempo de ti 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 

Utilizando set :

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

Utilizando único :

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

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] 

Aquí hay un ejemplo, devolviendo la lista sin repeticiones manteniendo el orden. No necesita ninguna importación externa.

 def GetListWithoutRepetitions(loInput): # return list, consisting of elements of list/tuple loInput, without repetitions. # Example: GetListWithoutRepetitions([None,None,1,1,2,2,3,3,3]) # Returns: [None, 1, 2, 3] if loInput==[]: return [] loOutput = [] if loInput[0] is None: oGroupElement=1 else: # loInput[0]<>None oGroupElement=None for oElement in loInput: if oElement<>oGroupElement: loOutput.append(oElement) oGroupElement = oElement return loOutput 

Marque esto si desea eliminar los duplicados (edición in situ en lugar de devolver una nueva lista) sin usar el conjunto incorporado, dict.keys, uniqify, counter

 >>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8] >>> for i in t: ... if i in t[t.index(i)+1:]: ... t.remove(i) ... >>> t [3, 1, 2, 5, 6, 7, 8] 

Creo que convertir para establecer es la forma más fácil de eliminar duplicados:

 list1 = [1,2,1] list1 = list(set(list1)) print list1 

Puedes usar set para eliminar duplicados:

 mylist = list(set(mylist)) 

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

 mylist.sort() 

Si desea conservar el orden, y no usar ningún módulo externo aquí, es una manera fácil de hacer esto:

 >>> 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, nueve vendrán 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 función fromkeys intenta crear una nueva clave, si el valor ya existe, simplemente la sobrescribirá. Sin embargo, esto no afectará al diccionario en absoluto, ya que fromkeys crea un diccionario en el que todas las teclas tienen el valor None , por lo que, de manera efectiva, elimina todos los duplicados de esta manera.