Max Fray
Tengo dos listas en Python:
temp1 = ['One', 'Two', 'Three', 'Four']
temp2 = ['One', 'Two']
Suponiendo que los elementos de cada lista son únicos, quiero crear una tercera lista con elementos de la primera lista que no están en la segunda lista:
temp3 = ['Three', 'Four']
¿Existen formas rápidas sin ciclos y comprobaciones?
marca byers
Todas las soluciones existentes ofrecen uno u otro de:
- Rendimiento más rápido que O(n*m).
- Conservar el orden de la lista de entrada.
Pero hasta ahora ninguna solución tiene ambos. 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é, además de preservar el orden, también es (ligeramente) más rápido que la resta de conjuntos porque no requiere la construcción de un conjunto innecesario. La diferencia de rendimiento sería más notable 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
-
Soporte adicional para esta respuesta: se encontró con un caso de uso en el que preservar el orden de la lista era importante para el rendimiento. Cuando trabajaba con objetos tarinfo o zipinfo, estaba usando la resta de conjuntos. Para excluir ciertos objetos tarinfo de ser extraídos del archivo. La creación de la nueva lista fue rápida pero muy lenta durante la extracción. La razón me evadió al principio. Resulta que reordenar la lista de objetos tarinfo causó una gran penalización en el rendimiento. Cambiar al método de comprensión de listas salvó el día.
– Ray Thompson
13 de diciembre de 2011 a las 0:26
-
@MarkByers: tal vez debería escribir una pregunta completamente nueva para esto. Pero, ¿cómo funcionaría esto en un forloop? Por ejemplo, si mi temp1 y temp2 siguen cambiando… ¿y quiero agregar la nueva información a temp3?
– Un hijo
9 de agosto de 2012 a las 17:57
-
@MarkByers: suena bien. Seguiré pensando en ello un rato. pero +1 para una gran solución.
– Un hijo
9 de agosto de 2012 a las 18:39
-
¿Podría explicar por qué su código lleva menos tiempo que el de la respuesta de Matt? @MarkByers
– trucos
5 de noviembre de 2015 a las 16:36
-
@haccks Porque verificar la membresía de una lista es una operación O (n) (iterar sobre toda la lista), pero verificar la membresía de un conjunto es O (1).
–Mark Byers
5 de noviembre de 2015 a las 16:57
-
¡Buen descubrimiento! Siempre pasé por alto esta sección de la documentación: docs.python.org/3/library/….
– usuario3521099
28 de diciembre de 2020 a las 16:09
-
Este es el mejor para una diferencia de 2 lados.
– EuberDeveloper
17/03/2021 a las 22:35
-
Definitivamente la mejor respuesta que aborda la pregunta del OP directamente “Obtener la diferencia entre dos listas”. Los otros son demasiado complicados con casos secundarios. Y no hay conversión de tipo de datos.
– Rich Lysakowski Doctorado
7 de abril de 2021 a las 3:25
-
¿Funciona mejor que cualquier otra solución a la vez?
– Gangula
13 de septiembre de 2021 a las 9:11
-
@Gangula Para ver la diferencia entre los dos métodos, agregue un valor a
temp2
que no está presente entemp1
e intenta de nuevo.– urig
19 oct 2021 a las 5:41
mate b
Podrías usar la lista de comprensión:
temp3 = [item for item in temp1 if item not in temp2]
-
Torneado
temp2
en un conjunto antes haría esto un poco más eficiente.– usuario355252
11 de agosto de 2010 a las 19:47
-
Cierto, depende de si a Ockonal le importan los duplicados o no (la pregunta original no lo dice)
– mate b
11 de agosto de 2010 a las 19:47
-
El comentario dice que las (listas|tuplas) no tienen duplicados.
– usuario395760
11 de agosto de 2010 a las 19:52
-
Voté a favor de su respuesta porque pensé que tenía razón sobre los duplicados al principio. Pero
item not in temp2
yitem not in set(temp2)
siempre devolverá los mismos resultados, independientemente de si hay duplicados o no entemp2
.– arekolek
07/03/2016 a las 22:42
-
Vote a favor por no exigir que los elementos de la lista sean hashable.
– Brent
11 de septiembre de 2017 a las 15:19
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 elemento 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}}}
Elemento agregado 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}}
Lista diferencia 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 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 con nombre:
>>> 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 agregado:
>>> t2.c = "new attribute"
>>> pprint(DeepDiff(t1, t2))
{'attribute_added': ['root.c'],
'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}
-
Torneado
temp2
en un conjunto antes haría esto un poco más eficiente.– usuario355252
11 de agosto de 2010 a las 19:47
-
Cierto, depende de si a Ockonal le importan los duplicados o no (la pregunta original no lo dice)
– mate b
11 de agosto de 2010 a las 19:47
-
El comentario dice que las (listas|tuplas) no tienen duplicados.
– usuario395760
11 de agosto de 2010 a las 19:52
-
Voté a favor de su respuesta porque pensé que tenía razón sobre los duplicados al principio. Pero
item not in temp2
yitem not in set(temp2)
siempre devolverá los mismos resultados, independientemente de si hay duplicados o no entemp2
.– arekolek
07/03/2016 a las 22:42
-
Vote a favor por no exigir que los elementos de la lista sean hashable.
– Brent
11 de septiembre de 2017 a las 15:19
maciej kucharz
Prueba esto:
temp3 = set(temp1) - set(temp2)
¿Los elementos son únicos garantizados? Si usted tiene
temp1 = ['One', 'One', 'One']
ytemp2 = ['One']
Quieres['One', 'One']
atrás, o[]
?– Michael Mrozek
11 de agosto de 2010 a las 19:43
@michael-mrozek son únicos.
– Max Fray
11 de agosto de 2010 a las 19:45
¿Quieres conservar el orden de los elementos?
–Mark Byers
11 de agosto de 2010 a las 19:49
¿Responde esto a tu pregunta? Encontrar elementos que no están en una lista
– Gonçalo Peres
28 de abril de 2021 a las 8:48