2009-11-04 10 views
10

Tengo dos listas muy grandes y recorrerlas una vez lleva al menos un segundo y tengo que hacerlo 200,000 veces. ¿Cuál es la forma más rápida de eliminar duplicados en dos listas para formar uno?Forma más rápida de eliminar duplicados en listas Python

+0

Sus tiempos indican que un bucle demora 55 horas en la actualidad. Sería interesante saber cuánto tardan las soluciones propuestas. – behindthefall

Respuesta

20

Esta es la manera más rápida que puedo pensar:

import itertools 
output_list = list(set(itertools.chain(first_list, second_list))) 

actualización Leve: Como jcd señala, dependiendo de su aplicación, es probable que no necesita convertir el resultado a una lista. Dado que un conjunto es iterable por sí mismo, es posible que pueda utilizar sólo directamente:

output_set = set(itertools.chain(first_list, second_list)) 
for item in output_set: 
    # do something 

Sin embargo, Aviso que cualquier solución que implique el uso de set() probablemente cambiar el orden de los elementos en la lista, por lo que no hay garantía de que los elementos estará en cualquier orden particular. Dicho esto, dado que estás combinando dos listas, es difícil encontrar una buena razón por la que necesitarías un pedido particular sobre ellas de todos modos, así que probablemente no es algo de lo que tengas que preocuparte.

+0

Oh, tu solución es mejor que la mía :) – shylent

+0

Gracias por las respuestas de todos, ¡todos me han ayudado mucho! :) – Cookies

+1

+1. Si la orden * es * importante, entonces quizás un conjunto ordenado lo haga: http://stackoverflow.com/questions/1653970/does-python-have-an-ordered-set – Stephan202

3
result = list(set(list1).union(set(list2))) 

Así es como yo lo haría. Aunque no estoy tan seguro del rendimiento, pero sin duda es mejor que hacerlo a mano.

+0

'set.union (self, other)' está bien con cualquier iterable como 'other' – u0b34a0f6ae

7

Como dice Daniel, un conjunto no puede contener entradas duplicadas - así concatenar las listas:

list1 + list2 

A continuación, convertir la nueva lista a un conjunto:

set(list1 + list2) 

Luego de vuelta a una lista:

list(set(list1 + list2)) 
+2

Gracias por explicar lo que mi código estaba haciendo. ¡Pásame! :-) Solo mencionaría que la razón por la que edité mi respuesta para usar 'itertools.chain()' en lugar de simplemente concatenar las listas es porque evita tener que asignar una tercera lista grande en la memoria. El constructor 'set()' en realidad no necesita una lista, solo necesita un iterable que pueda iterar sobre todos los elementos, y 'itertools.chain()' lo hace de manera más eficiente (evitando copiar). –

11

Recomendaría algo como esto:

def combine_lists(list1, list2): 
    s = set(list1) 
    s.update(list2) 
    return list(s) 

Esto elimina el problema de crear una lista de monstruos de la concatenación de los dos primeros.

Dependiendo de lo que esté haciendo con la salida, no se moleste en convertir nuevamente a una lista. Si el orden es importante, es posible que necesite algún tipo de decorar/ordenar/decodificar las travesuras alrededor de esto.

+2

De acuerdo, no hay necesidad de concatenar las dos listas, eso solo desperdicia memoria. Me interesaría ver la diferencia de rendimiento entre llamar 's.update (list2)' versus el enfoque de iterador que utilicé arriba. Su enfoque puede ser un poco más rápido. Sin embargo, como usted señala, obtiene un ahorro de rendimiento mucho mayor simplemente al no volver a una lista al final. –

+1

Corrí algunos timeits, y parece variar, que es más rápido, pero nunca en más de 5% o 10% de una forma u otra. Yo diría que es un empate. – jcdyer

+0

Dado que itertools solo encadena dos objetos, diría que su impacto es bastante mínimo, por lo que la pregunta es si hay una diferencia significativa entre set() ing big list o set() la mitad de esa lista y .update () ing el resto de eso. Parece que no hay. – jcdyer

Cuestiones relacionadas