Consigue diferencia entre dos listas

Tengo dos listas en Python, como estas:

temp1 = ['One', 'Two', 'Three', 'Four'] temp2 = ['One', 'Two'] 

Necesito crear una tercera lista con elementos de la primera lista que no están presentes en la segunda. Del ejemplo tengo que obtener:

 temp3 = ['Three', 'Four'] 

¿Hay formas rápidas sin ciclos y chequeo?

 In [5]: list(set(temp1) - set(temp2)) Out[5]: ['Four', 'Three'] 

Ten cuidado con eso

 In [5]: set([1, 2]) - set([2, 3]) Out[5]: set([1]) 

donde puede esperar / querer que sea igual al set([1, 3]) . Si desea set([1, 3]) como respuesta, deberá usar set([1, 2]).symmetric_difference(set([2, 3])) .

Todas las soluciones existentes ofrecen una u otra de:

  • Más rápido que el rendimiento de O (n * m).
  • Conservar el orden de la lista de entrada.

Pero hasta ahora ninguna solución tiene ambas. Si quieres ambos, prueba esto:

 s = set(temp2) temp3 = [x for x in temp1 if x not in s] 

Prueba de rendimiento

 import timeit init = 'temp1 = list(range(100)); temp2 = [i * 2 for i in range(50)]' print timeit.timeit('list(set(temp1) - set(temp2))', init, number = 100000) print timeit.timeit('s = set(temp2);[x for x in temp1 if x not in s]', init, number = 100000) print timeit.timeit('[item for item in temp1 if item not in temp2]', init, number = 100000) 

Resultados:

 4.34620224079 # ars' answer 4.2770634955 # This answer 30.7715615392 # matt b's answer 

El método que presenté y el orden de conservación también son (ligeramente) más rápidos que la resta del conjunto porque no requiere la construcción de un conjunto innecesario. La diferencia de rendimiento sería más notoria si la primera lista es considerablemente más larga que la segunda y si el hashing es costoso. Aquí hay una segunda prueba que demuestra esto:

 init = ''' temp1 = [str(i) for i in range(100000)] temp2 = [str(i * 2) for i in range(50)] ''' 

Resultados:

 11.3836875916 # ars' answer 3.63890368748 # this answer (3 times faster!) 37.7445402279 # matt b's answer 
 temp3 = [item for item in temp1 if item not in temp2] 

La diferencia entre dos listas (por ejemplo, lista1 y lista2) se puede encontrar usando la siguiente función simple.

 def diff(list1, list2): c = set(list1).union(set(list2)) # or c = set(list1) | set(list2) d = set(list1).intersection(set(list2)) # or d = set(list1) & set(list2) return list(c - d) 

o

 def diff(list1, list2): return list(set(list1).symmetric_difference(set(list2))) # or return list(set(list1) ^ set(list2)) 

Usando la función anterior, la diferencia se puede encontrar usando diff(temp2, temp1) o diff(temp1, temp2) . Ambos darán el resultado ['Four', 'Three'] . No tiene que preocuparse por el orden de la lista o qué lista se debe dar primero.

Referencia de documento de Python

En caso de que quiera la diferencia recursivamente, he escrito un paquete para python: https://github.com/seperman/deepdiff

Instalación

Instalar desde PyPi:

 pip install deepdiff 

Ejemplo de uso

Importador

 >>> from deepdiff import DeepDiff >>> from pprint import pprint >>> from __future__ import print_function # In case running on Python 2 

El mismo objeto devuelve vacío

 >>> t1 = {1:1, 2:2, 3:3} >>> t2 = t1 >>> print(DeepDiff(t1, t2)) {} 

El tipo de un artículo ha cambiado

 >>> t1 = {1:1, 2:2, 3:3} >>> t2 = {1:1, 2:"2", 3:3} >>> pprint(DeepDiff(t1, t2), indent=2) { 'type_changes': { 'root[2]': { 'newtype': , 'newvalue': '2', 'oldtype': , 'oldvalue': 2}}} 

El valor de un artículo ha cambiado

 >>> t1 = {1:1, 2:2, 3:3} >>> t2 = {1:1, 2:4, 3:3} >>> pprint(DeepDiff(t1, t2), indent=2) {'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}} 

Artículo añadido y / o eliminado

 >>> t1 = {1:1, 2:2, 3:3, 4:4} >>> t2 = {1:1, 2:4, 3:3, 5:5, 6:6} >>> ddiff = DeepDiff(t1, t2) >>> pprint (ddiff) {'dic_item_added': ['root[5]', 'root[6]'], 'dic_item_removed': ['root[4]'], 'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}} 

Diferencia de cadena

 >>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world"}} >>> t2 = {1:1, 2:4, 3:3, 4:{"a":"hello", "b":"world!"}} >>> ddiff = DeepDiff(t1, t2) >>> pprint (ddiff, indent = 2) { 'values_changed': { 'root[2]': {'newvalue': 4, 'oldvalue': 2}, "root[4]['b']": { 'newvalue': 'world!', 'oldvalue': 'world'}}} 

Diferencia de cadena 2

 >>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world!\nGoodbye!\n1\n2\nEnd"}} >>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n1\n2\nEnd"}} >>> ddiff = DeepDiff(t1, t2) >>> pprint (ddiff, indent = 2) { 'values_changed': { "root[4]['b']": { 'diff': '--- \n' '+++ \n' '@@ -1,5 +1,4 @@\n' '-world!\n' '-Goodbye!\n' '+world\n' ' 1\n' ' 2\n' ' End', 'newvalue': 'world\n1\n2\nEnd', 'oldvalue': 'world!\n' 'Goodbye!\n' '1\n' '2\n' 'End'}}} >>> >>> print (ddiff['values_changed']["root[4]['b']"]["diff"]) --- +++ @@ -1,5 +1,4 @@ -world! -Goodbye! +world 1 2 End 

Cambio de tipo

 >>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}} >>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n\n\nEnd"}} >>> ddiff = DeepDiff(t1, t2) >>> pprint (ddiff, indent = 2) { 'type_changes': { "root[4]['b']": { 'newtype': , 'newvalue': 'world\n\n\nEnd', 'oldtype': , 'oldvalue': [1, 2, 3]}}} 

Diferencia de lista

 >>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3, 4]}} >>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2]}} >>> ddiff = DeepDiff(t1, t2) >>> pprint (ddiff, indent = 2) {'iterable_item_removed': {"root[4]['b'][2]": 3, "root[4]['b'][3]": 4}} 

Diferencia de lista 2:

 >>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}} >>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}} >>> ddiff = DeepDiff(t1, t2) >>> pprint (ddiff, indent = 2) { 'iterable_item_added': {"root[4]['b'][3]": 3}, 'values_changed': { "root[4]['b'][1]": {'newvalue': 3, 'oldvalue': 2}, "root[4]['b'][2]": {'newvalue': 2, 'oldvalue': 3}}} 

Enumere las diferencias ignorando el orden o los duplicados: (con los mismos diccionarios que arriba)

 >>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}} >>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}} >>> ddiff = DeepDiff(t1, t2, ignore_order=True) >>> print (ddiff) {} 

Lista que contiene el diccionario:

 >>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:1, 2:2}]}} >>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:3}]}} >>> ddiff = DeepDiff(t1, t2) >>> pprint (ddiff, indent = 2) { 'dic_item_removed': ["root[4]['b'][2][2]"], 'values_changed': {"root[4]['b'][2][1]": {'newvalue': 3, 'oldvalue': 1}}} 

Conjuntos:

 >>> t1 = {1, 2, 8} >>> t2 = {1, 2, 3, 5} >>> ddiff = DeepDiff(t1, t2) >>> pprint (DeepDiff(t1, t2)) {'set_item_added': ['root[3]', 'root[5]'], 'set_item_removed': ['root[8]']} 

Tuplas nombradas:

 >>> from collections import namedtuple >>> Point = namedtuple('Point', ['x', 'y']) >>> t1 = Point(x=11, y=22) >>> t2 = Point(x=11, y=23) >>> pprint (DeepDiff(t1, t2)) {'values_changed': {'root.y': {'newvalue': 23, 'oldvalue': 22}}} 

Objetos personalizados:

 >>> class ClassA(object): ... a = 1 ... def __init__(self, b): ... self.b = b ... >>> t1 = ClassA(1) >>> t2 = ClassA(2) >>> >>> pprint(DeepDiff(t1, t2)) {'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}} 

Atributo de objeto añadido:

 >>> t2.c = "new attribute" >>> pprint(DeepDiff(t1, t2)) {'attribute_added': ['root.c'], 'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}} 

Si realmente estás buscando en el rendimiento, ¡usa numpy!

Aquí está el cuaderno completo como una esencia en github con la comparación entre list, numpy y pandas.

https://gist.github.com/denfromufa/2821ff59b02e9482be15d27f2bbd4451

introduzca la descripción de la imagen aquí

Voy a tirar ya que ninguna de las soluciones presentes produce una tupla:

 temp3 = tuple(set(temp1) - set(temp2)) 

alternativamente:

 #edited using @Mark Byers idea. If you accept this one as answer, just accept his instead. temp3 = tuple(x for x in temp1 if x not in set(temp2)) 

Al igual que las otras respuestas que no producen tuplas en esta dirección, conserva el orden.

Se puede hacer usando el operador Python XOR.

  • Esto eliminará los duplicados en cada lista.
  • Esto mostrará la diferencia de temp1 de temp2 y temp2 de temp1.

 set(temp1) ^ set(temp2) 

forma más sencilla,

usar set (). diferencia (set ())

 list_a = [1,2,3] list_b = [2,3] print set(list_a).difference(set(list_b)) 

la respuesta está set([1])

puede imprimir como una lista,

 print list(set(list_a).difference(set(list_b))) 

Prueba esto:

 temp3 = set(temp1) - set(temp2) 

esto podría ser incluso más rápido que la lista de comprensión de Mark:

 list(itertools.filterfalse(set(temp2).__contains__, temp1)) 

Quería algo que tomaría dos listas y podría hacer lo que diff en bash hace. Ya que esta pregunta aparece primero cuando buscas “python diff two lists” y no es muy específica, publicaré lo que se me ocurrió.

Usando SequenceMather de difflib puedes comparar dos listas como lo hace diff . Ninguna de las otras respuestas le dirá la posición donde se produce la diferencia, pero esta sí lo hace. Algunas respuestas dan la diferencia en una sola dirección. Algunos reordenan los elementos. Algunos no manejan duplicados. Pero esta solución te da una verdadera diferencia entre dos listas:

 a = 'A quick fox jumps the lazy dog'.split() b = 'A quick brown mouse jumps over the dog'.split() from difflib import SequenceMatcher for tag, i, j, k, l in SequenceMatcher(None, a, b).get_opcodes(): if tag == 'equal': print('both have', a[i:j]) if tag in ('delete', 'replace'): print(' 1st has', a[i:j]) if tag in ('insert', 'replace'): print(' 2nd has', b[k:l]) 

Esto produce:

 both have ['A', 'quick'] 1st has ['fox'] 2nd has ['brown', 'mouse'] both have ['jumps'] 2nd has ['over'] both have ['the'] 1st has ['lazy'] both have ['dog'] 

Por supuesto, si su aplicación hace las mismas suposiciones que las otras respuestas, se beneficiará más de ellas. Pero si está buscando una verdadera funcionalidad de diff , esta es la única manera de hacerlo.

Por ejemplo, ninguna de las otras respuestas podría manejar:

 a = [1,2,3,4,5] b = [5,4,3,2,1] 

Pero este hace:

  2nd has [5, 4, 3, 2] both have [1] 1st has [2, 3, 4, 5] 

Podría usar un método ingenuo si los elementos de la lista de diferencias se ordenan y establecen.

 list1=[1,2,3,4,5] list2=[1,2,3] print list1[len(list2):] 

o con métodos de configuración nativos:

 subset=set(list1).difference(list2) print subset import timeit init = 'temp1 = list(range(100)); temp2 = [i * 2 for i in range(50)]' print "Naive solution: ", timeit.timeit('temp1[len(temp2):]', init, number = 100000) print "Native set solution: ", timeit.timeit('set(temp1).difference(temp2)', init, number = 100000) 

Solución ingenua: 0.0787101593292

Solución nativa: 0.998837615564

Aquí hay una respuesta Counter para el caso más simple.

Esto es más corto que el anterior que hace diferencias de dos vías porque solo hace exactamente lo que la pregunta hace: genera una lista de lo que está en la primera lista pero no la segunda.

 from collections import Counter lst1 = ['One', 'Two', 'Three', 'Four'] lst2 = ['One', 'Two'] c1 = Counter(lst1) c2 = Counter(lst2) diff = list((c1 - c2).elements()) 

Alternativamente, dependiendo de sus preferencias de legibilidad, se convierte en una sola línea decente:

 diff = list((Counter(lst1) - Counter(lst2)).elements()) 

Salida:

 ['Three', 'Four'] 

Tenga en cuenta que puede eliminar la llamada de list(...) si solo está iterando sobre ella.

Debido a que esta solución usa contadores, maneja las cantidades correctamente frente a las muchas respuestas basadas en conjuntos. Por ejemplo en esta entrada:

 lst1 = ['One', 'Two', 'Two', 'Two', 'Three', 'Three', 'Four'] lst2 = ['One', 'Two'] 

La salida es:

 ['Two', 'Two', 'Three', 'Three', 'Four'] 

Si se encuentra con TypeError: unhashable type: 'list' necesita convertir listas o conjuntos en tuplas, por ejemplo

 set(map(tuple, list_of_lists1)).symmetric_difference(set(map(tuple, list_of_lists2))) 

Consulte también ¿Cómo comparar una lista de listas / conjuntos en python?

Estoy demasiado atrasado en el juego para esto, pero puedes hacer una comparación del rendimiento de algunos de los códigos mencionados anteriormente. Dos de los candidatos más rápidos son:

 list(set(x).symmetric_difference(set(y))) list(set(x) ^ set(y)) 

Pido disculpas por el nivel elemental de encoding.

 import time import random from itertools import filterfalse # 1 - performance (time taken) # 2 - correctness (answer - 1,4,5,6) # set performance performance = 1 numberoftests = 7 def answer(x,y,z): if z == 0: start = time.clock() lists = (str(list(set(x)-set(y))+list(set(y)-set(y)))) times = ("1 = " + str(time.clock() - start)) return (lists,times) elif z == 1: start = time.clock() lists = (str(list(set(x).symmetric_difference(set(y))))) times = ("2 = " + str(time.clock() - start)) return (lists,times) elif z == 2: start = time.clock() lists = (str(list(set(x) ^ set(y)))) times = ("3 = " + str(time.clock() - start)) return (lists,times) elif z == 3: start = time.clock() lists = (filterfalse(set(y).__contains__, x)) times = ("4 = " + str(time.clock() - start)) return (lists,times) elif z == 4: start = time.clock() lists = (tuple(set(x) - set(y))) times = ("5 = " + str(time.clock() - start)) return (lists,times) elif z == 5: start = time.clock() lists = ([tt for tt in x if tt not in y]) times = ("6 = " + str(time.clock() - start)) return (lists,times) else: start = time.clock() Xarray = [iDa for iDa in x if iDa not in y] Yarray = [iDb for iDb in y if iDb not in x] lists = (str(Xarray + Yarray)) times = ("7 = " + str(time.clock() - start)) return (lists,times) n = numberoftests if performance == 2: a = [1,2,3,4,5] b = [3,2,6] for c in range(0,n): d = answer(a,b,c) print(d[0]) elif performance == 1: for tests in range(0,10): print("Test Number" + str(tests + 1)) a = random.sample(range(1, 900000), 9999) b = random.sample(range(1, 900000), 9999) for c in range(0,n): #if c not in (1,4,5,6): d = answer(a,b,c) print(d[1]) 

Esta es otra solución:

 def diff(a, b): xa = [i for i in set(a) if i not in b] xb = [i for i in set(b) if i not in a] return xa + xb 

versión de una sola línea de la solución arulmr

 def diff(listA, listB): return set(listA) - set(listB) | set(listA) -set(listB) 

Si quieres algo más parecido a un conjunto de cambios … podrías usar Contador

 from collections import Counter def diff(a, b): """ more verbose than needs to be, for clarity """ ca, cb = Counter(a), Counter(b) to_add = cb - ca to_remove = ca - cb changes = Counter(to_add) changes.subtract(to_remove) return changes lista = ['one', 'three', 'four', 'four', 'one'] listb = ['one', 'two', 'three'] In [127]: diff(lista, listb) Out[127]: Counter({'two': 1, 'one': -1, 'four': -2}) # in order to go from lista to list b, you need to add a "two", remove a "one", and remove two "four"s In [128]: diff(listb, lista) Out[128]: Counter({'four': 2, 'one': 1, 'two': -1}) # in order to go from listb to lista, you must add two "four"s, add a "one", and remove a "two" 

Podemos calcular la intersección menos la unión de listas:

 temp1 = ['One', 'Two', 'Three', 'Four'] temp2 = ['One', 'Two', 'Five'] set(temp1+temp2)-(set(temp1)&set(temp2)) Out: set(['Four', 'Five', 'Three']) 

Esto se puede resolver con una sola línea. A la pregunta se le dan dos listas (temp1 y temp2) que devuelven su diferencia en una tercera lista (temp3).

 temp3 = list(set(temp1).difference(set(temp2))) 

Aquí hay algunas formas sencillas de preservar el orden de diferenciar dos listas de cadenas.

Código

Un enfoque inusual utilizando pathlib :

 import pathlib temp1 = ["One", "Two", "Three", "Four"] temp2 = ["One", "Two"] p = pathlib.Path(*temp1) r = p.relative_to(*temp2) list(r.parts) # ['Three', 'Four'] 

Esto supone que ambas listas contienen cadenas con comienzos equivalentes. Vea la documentación para más detalles. Tenga en cuenta que no es particularmente rápido en comparación con las operaciones de configuración.


Una implementación directa utilizando itertools.zip_longest :

 import itertools as it [x for x, y in it.zip_longest(temp1, temp2) if x != y] # ['Three', 'Four'] 

Digamos que tenemos dos listas

 list1 = [1, 3, 5, 7, 9] list2 = [1, 2, 3, 4, 5] 

Podemos ver en las dos listas anteriores que los elementos 1, 3, 5 existen en la lista 2 y que los elementos 7, 9 no. Por otro lado, los elementos 1, 3, 5 existen en la lista 1 y los elementos 2, 4 no.

¿Cuál es la mejor solución para devolver una nueva lista que contenga los artículos 7, 9 y 2, 4?

Todas las respuestas anteriores encuentran la solución, ¿ahora cuál es la más óptima?

 def difference(list1, list2): new_list = [] for i in list1: if i not in list2: new_list.append(i) for j in list2: if j not in list1: new_list.append(j) return new_list 

versus

 def sym_diff(list1, list2): return list(set(list1).symmetric_difference(set(list2))) 

Usando timeit podemos ver los resultados.

 t1 = timeit.Timer("difference(list1, list2)", "from __main__ import difference, list1, list2") t2 = timeit.Timer("sym_diff(list1, list2)", "from __main__ import sym_diff, list1, list2") print('Using two for loops', t1.timeit(number=100000), 'Milliseconds') print('Using two for loops', t2.timeit(number=100000), 'Milliseconds') 

devoluciones

 [7, 9, 2, 4] Using two for loops 0.11572412995155901 Milliseconds Using symmetric_difference 0.11285737506113946 Milliseconds Process finished with exit code 0 

Esta es una forma sencilla de distinguir dos listas (cualquiera que sea el contenido), puede obtener el resultado como se muestra a continuación:

 >>> from sets import Set >>> >>> l1 = ['xvda', False, 'xvdbb', 12, 'xvdbc'] >>> l2 = ['xvda', 'xvdbb', 'xvdbc', 'xvdbd', None] >>> >>> Set(l1).symmetric_difference(Set(l2)) Set([False, 'xvdbd', None, 12]) 

Espero que esto sea de ayuda.

 tweets=['manoj', 'shekhar', 'manoj', 'rahul', 'mohit','jyohit','sankar','pappu'] netweets=['manoj','pappu', 'shekhar','mohit','gourav'] netweet = [] for i in tweets: if i not in netweets: netweet.append(i) print(netweet) 
 (list(set(a)-set(b))+list(set(b)-set(a)))