Pregunta Eliminar duplicados en listas


Casi necesito escribir un programa para verificar si una lista tiene algún duplicado y si lo hace, los elimina y 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

612
2017-11-01 00:45


origen


Respuestas:


El enfoque común para obtener una colección única de artículos es usar un set. Los conjuntos son desordenado colecciones de distinto objetos. Para crear un conjunto desde cualquier iterable, simplemente puede pasarlo al built-in set() función. Si luego necesita una lista real de nuevo, puede pasar de manera similar el conjunto al list() función.

El siguiente ejemplo debe abarcar todo lo que intenta 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 son colecciones desordenadas, por lo que se pierde el orden. Al convertir un conjunto a una lista, se crea un orden arbitrario.

Si el orden es importante para ti, entonces tendrás 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 ventaja de crear primero un diccionario y luego crear una lista a partir de él. Entonces, si realmente no necesita conservar el pedido, es mejor que use un conjunto. Revisa 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 así como el OrderedDict solución requiere que sus artículos sean hashable. Esto generalmente significa que tienen que ser inmutables. Si tiene que tratar con elementos que no son lavables (por ejemplo, los objetos de la lista), tendrá que usar un enfoque lento en el que básicamente tendrá que comparar cada elemento con cada elemento en un bucle anidado.


1060
2017-11-01 00:49



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 volvió tanto ordenado como compacto. (Esta característica es válida para CPython y PyPy, pero puede no presentarse en otras implementaciones). Eso nos brinda una nueva forma más rápida de deduplicación al tiempo que conservamos el orden:

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

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

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

300
2017-11-01 00:53



Es un trazador de líneas: 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 dos líneas:

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

Aquí usamos 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 particular. Insertamos True como valores, pero podríamos insertar cualquier cosa, los valores simplemente no se usan. (set funciona mucho como un dictcon valores ignorados, también.)


157
2017-11-01 00:49



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

66
2018-05-14 12:39



Si no le importa el pedido, simplemente haga esto:

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

UN set está garantizado para no tener duplicados.


60
2017-11-01 00:49



Para hacer una nueva lista que retenga el orden de los primeros elementos de los 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 estarán [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 importar.


28
2017-07-05 03:39



Otra forma de hacer:

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

18
2018-01-01 15:39



Un colega me ha enviado la respuesta aceptada como parte de su código para una revisión del código hoy. Si bien admiro la elegancia de la respuesta en cuestión, no estoy contento con el rendimiento. He probado esta solución (yo uso conjunto 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 fueron ú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 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 el 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

16
2017-09-17 09:52



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]

13
2018-04-14 23:33



También hay soluciones usando Pandas y Numpy. Ambos regresan matriz numpy por lo 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']

La solución 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 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 t2 se devuelve ordenado Si desea tener el orden de uso preservado 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 comprobar si las matrices anidadas son únicas a lo largo de un eje seleccionado.


12
2017-07-03 12:45



Tenía una dict en mi lista, así que no pude usar el enfoque anterior. Obtuve el error:

TypeError: unhashable type:

Entonces, si te importa orden y / o algunos artículos son irresistible. Entonces puede 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 que la comprensión de la lista 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

11
2018-06-06 15:25