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
python
algorithm
list
duplicates
intersection
Neemaximo
fuente
fuente
Respuestas:
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 laset()
función incorporada. Si más tarde necesita una lista real nuevamente, puede pasar el conjunto de manera similar a lalist()
función.El siguiente ejemplo debería cubrir todo lo que intente hacer:
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
OrderedDict
mantener el orden de las claves durante la inserción: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):
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
set
como lasOrderedDict
/dict
requieren 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.fuente
En Python 2.7 , la nueva forma de eliminar duplicados de un iterable mientras se mantiene en el orden original es:
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:
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:
fuente
TypeError: unhashable type: 'dictlist'
Es una frase:
list(set(source_list))
hará el truco.A
set
es algo que no puede tener duplicados.Actualización: un enfoque de preservación de pedidos consta de dos líneas:
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. InsertamosTrue
como valores, pero podríamos insertar cualquier cosa, los valores simplemente no se usan. (set
funciona muy parecido a undict
con valores ignorados, también.)fuente
source_list
es hashable.fuente
frozenset
funcione con contenido no hashable. Todavía recibo el error no hashable cuando lo usofrozenset
.Si no te importa el pedido, solo haz esto:
Se
set
garantiza que A no tiene duplicados.fuente
l
sea hashable.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]
entoncesnewlist
será[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.
fuente
set
yOrderedDict
pueden tener menor complejidad de tiempo amortizado.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)
Para comparar la eficiencia, utilicé una muestra aleatoria de 100 enteros: 62 eran únicos
Aquí están los resultados de las mediciones.
Bueno, ¿qué sucede si se elimina el conjunto de la solución?
El resultado no es tan malo como con el OrderedDict , pero sigue siendo más de 3 veces la solución original.
fuente
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)]
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.Solución de pandas
Usando la función Pandas
unique()
:Solución de Numpy
Usando la función numpy
unique()
.Tenga en cuenta que numpy.unique () también ordena los valores . Entonces la lista
t2
se devuelve ordenada. Si desea conservar el orden, use como en esta respuesta :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.
fuente
Otra forma de hacer:
fuente
keys()
devuelve un objeto de vista de diccionario, no una lista.Simple y fácil:
Salida:
fuente
in
es operación O (n) ycleanlist
tendrá como máximon
números => peor de los casos ~ O (n ^ 2)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))
ifmy_list
es 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:
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
(Aumentado)
Hashables ordenados
(Aumentado)
Ordenadas inquebrantables
(Aumentado)
fuente
Tenía un dict en mi lista, por lo que no podía usar el enfoque anterior. Recibí el error:
Entonces, si le importa el orden y / o algunos artículos son inquebrantables . Entonces te puede resultar útil:
Algunos pueden considerar que la comprensión de listas con un efecto secundario no es una buena solución. Aquí hay una alternativa:
fuente
map
con 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 pasarunique_list.append
.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
+list
que se limitan a entradas hashaable. Aquí hay una solución O (nlogn) independiente de hash:La actualización agregó el
key
argumento, la documentación y la compatibilidad con Python 3.fuente
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.reduce()
ya está trabajando en una colección ordenadasrt_enum
, ¿por qué solicitósorted
nuevamente?Si desea preservar el pedido y no utilizar ningún módulo externo, esta es una manera fácil de hacerlo:
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
pero es mucho más corto y corre más rápido.
Esto funciona porque cada vez que la
fromkeys
función intenta crear una nueva clave, si el valor ya existe, simplemente lo sobrescribirá. Sin embargo, esto no afectará en absoluto al diccionario, ya quefromkeys
crea un diccionario donde todas las claves tienen el valorNone
, por lo que efectivamente elimina todos los duplicados de esta manera.fuente
También puedes hacer esto:
La razón por la que funciona anteriormente es que ese
index
método devuelve solo el primer índice de un elemento. Los elementos duplicados tienen índices más altos. Consulte aquí :fuente
list.index
es una operación de tiempo lineal, lo que hace que su solución sea cuadrática.Intenta usar conjuntos:
fuente
Reduzca la variante con la preservación de pedidos:
Supongamos que tenemos una lista:
Reducir variante (ineficiente):
5 veces más rápido pero más sofisticado
Explicación:
fuente
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
fuente
Puede usar la siguiente función:
Ejemplo :
Uso:
['this', 'is', 'a', 'list', 'with', 'dupicates', 'in', 'the']
fuente
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:
Esto devuelve un generador / iterador, por lo que puede usarlo en cualquier lugar donde pueda usar un iterador.
Salida:
Si quieres un
list
, puedes hacer esto:Salida:
fuente
seen = set(iterable); for item in seen: yield item
Es casi seguro que es más rápido. (No he probado este caso específico, pero esa sería mi suposición.)Sin usar set
fuente
Puede usar
set
para eliminar duplicados:Pero tenga en cuenta que los resultados serán desordenados. Si eso es un problema:
fuente
Un mejor enfoque más podría ser,
y el orden permanece preservado.
fuente
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:
fuente
list
); 2. Su método escala extremadamente mal: es cuadrático en el número de elementos enlist
.el siguiente código es simple para eliminar duplicados en la lista
vuelve [1,2,3,4]
fuente
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!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 devuelveNone
como resultado, que se evalúa comoFalse
, por lo que el lado derecho deor
siempre sería el resultado de dicha expresión.Míralo tú mismo
fuente
Usando set :
Usando único :
fuente
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.
Esto le dará x con los duplicados eliminados pero conservando el orden.
fuente
De manera muy simple en Python 3:
fuente
sorted(list(...))
es redundante (sorted
ya convierte implícitamente su argumento en nuevolist
, lo ordena, luego devuelve el nuevolist
, por lo que usar ambos significa hacer un temporal innecesariolist
). Use sololist
si el resultado no necesita ser ordenado, use solosorted
si el resultado necesita ser ordenado.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
Obtendrás el resultado
Método 2: caso especial
El caso especial para procesar no compartible ( códigos de 3 líneas )
Obtendrás el resultado:
Debido a que la tupla es hashable y puedes convertir datos entre la lista y la tupla fácilmente
fuente