two lists create python performance list set set-difference
itertools.zip_longest

python - lists - Consigue diferencia entre dos listas



set to list python (25)

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?


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. Ver la docs 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'']


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


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, ¿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


En caso de que desee 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'': <class ''str''>, ''newvalue'': ''2'', ''oldtype'': <class ''int''>, ''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'': <class ''str''>, ''newvalue'': ''world/n/n/nEnd'', ''oldtype'': <class ''list''>, ''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 la diferencia 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}}}


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


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.


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

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


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 codificación.

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


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


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


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


Prueba esto:

temp3 = set(temp1) - set(temp2)


Quería algo que tomara dos listas y podría hacer lo que hace diff en bash . 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]


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)


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"




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


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, preserva el orden.


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

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


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


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)


(list(set(a)-set(b))+list(set(b)-set(a)))


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 podría esperar / querer que sea igual al set([1, 3]) . Si quiere set([1, 3]) como respuesta, deberá usar set([1, 2]).symmetric_difference(set([2, 3])) .


temp3 = [item for item in temp1 if item not in temp2]