Encuentra elementos no comunes en las listas.

Estoy tratando de escribir un fragmento de código que puede factorizar automáticamente una expresión. Por ejemplo, si tengo dos listas [1,2,3,4] y [2,3,5], el código debería poder encontrar los elementos comunes en las dos listas, [2,3], y combinar El rest de los elementos se juntan en una nueva lista, siendo [1,4,5].

De este post: ¿Cómo encontrar la intersección de la lista? Veo que los elementos comunes se pueden encontrar por

set([1,2,3,4]&set([2,3,5]). 

¿Hay una manera fácil de recuperar elementos no comunes de cada lista, en mi ejemplo siendo [1,4] y [5]?

Puedo seguir adelante y hacer un bucle for:

 lists = [[1,2,3,4],[2,3,5]] conCommon = [] common = [2,3] for elem in lists: for elem in eachList: if elem not in common: nonCommon += elem 

Pero esto parece redundante e ineficiente. ¿Python proporciona alguna función útil que pueda hacer eso? ¡¡Gracias por adelantado!!

Use el operador de diferencia simétrica para los set s (también conocido como el operador XOR):

 >>> set([1,2,3]) ^ set([3,4,5]) set([1, 2, 4, 5]) 

Puede utilizar el concepto Intersección para tratar este tipo de problemas.

 b1 = [1,2,3,4,5,9,11,15] b2 = [4,5,6,7,8] set(b1).intersection(b2) Out[22]: {4, 5} 

Lo mejor de usar este código es que también funciona bastante rápido para datos grandes. Tengo b1 con 607139 y b2 con 296029 elementos cuando uso esta lógica, obtengo mis resultados en 2,9 segundos.

Pregunta antigua, pero parece que python tiene una función incorporada para proporcionar exactamente lo que estás buscando: .difference() .

EJEMPLO

 list_one = [1,2,3,4] list_two = [2,3,5] one_not_two = set(list_one).difference(list_two) # set([1, 4]) two_not_one = set(list_two).difference(list_one) # set([5]) 

Esto también podría ser escrito como:

 one_not_two = set(list_one) - set(list_two) 

Sincronización

Realicé algunas pruebas de sincronización en ambas y parece que .difference() tiene una ligera ventaja, de 10 a 15%, pero cada método tomó aproximadamente un octavo de segundo para filtrar elementos 1M (enteros aleatorios entre 500 y 100,000) , así que a menos que seas muy sensible al tiempo, probablemente sea irrelevante.

Otras notas

Parece que el OP está buscando una solución que proporcione dos listas separadas (o conjuntos), una donde la primera contiene elementos que no están en la segunda y viceversa. La mayoría de las respuestas anteriores devuelven una sola lista o conjunto que incluye todos los elementos.

También está la pregunta de si los elementos que pueden estar duplicados en la primera lista deben contarse varias veces, o solo una vez.

Si el OP desea mantener duplicados, se podría usar una lista de comprensión, por ejemplo:

 one_not_two = [ x for x in list_one if x not in list_two ] two_not_one = [ x for x in list_two if x not in list_one ] 

… que es aproximadamente la misma solución que se plantea en la pregunta original, solo un poco más limpia. Este método mantendría los duplicados de la lista original pero es considerablemente más lento (como varios órdenes de magnitud) para conjuntos de datos más grandes.

Puede utilizar el método de atributo .__xor__ .

 set([1,2,3,4]).__xor__(set([2,3,5])) 

o

 a = set([1,2,3,4]) b = set([2,3,5]) a.__xor__(b)