Pregunta

Tengo dos listas en Python, como los siguientes:

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

Es necesario crear una tercera lista con los elementos de la primera lista, que no están presentes en la segunda. A partir del ejemplo que tengo que:

temp3 = ['Three', 'Four']

¿Hay alguna manera rápida sin ciclos y corriente?

¿Fue útil?

Solución

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

Tenga en cuenta que

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

donde se podría esperar / quiero que igual set([1, 3]). Si lo hace set([1, 3]) quiere como su respuesta, que necesita para su uso set([1, 2]).symmetric_difference(set([2, 3])).

Otros consejos

Las soluciones existentes todos ofrecen ya sea uno u otro de:

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

Pero hasta ahora ninguna solución tiene ambas cosas. Si quieres tanto, intente lo siguiente:

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 presenté, así como la preservación del orden también es (ligeramente) más rápido que la sustracción conjunto, ya que 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 largo que el segundo y si hash es caro. He aquí 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 (list1 digamos y list2) se puede encontrar utilizando 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))

Mediante el uso de la función anterior, la diferencia se puede encontrar utilizando diff(temp2, temp1) o diff(temp1, temp2). Tanto dará la ['Four', 'Three'] resultado. Usted no tiene que preocuparse por el orden de la lista o qué lista debe ser dado en primer lugar.

Python referencia doc

En caso de que desee la diferencia de forma recursiva, he escrito un paquete de Python: https://github.com/seperman/deepdiff

instalación

Instalar desde PyPi:

pip install deepdiff

Ejemplo de uso

Importar

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

retornos mismo objeto vacío

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

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 elemento 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}}}

añade y / o se elimina del artículo

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

Tipo de cambio

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

Lista diferencia

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

Lista diferencia orden o duplicados ignorar: (con los mismos diccionarios que el anterior)

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

Sets:

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

El nombre Tuplas:

>>> 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 usted realmente está buscando en el rendimiento, a continuación, utilizar numpy!

Aquí está el cuaderno lleno como una esencia en github con la comparación entre la lista, numpy, y los osos panda.

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

 introducir descripción de la imagen aquí

La mayoría de forma sencilla,

uso set (). Diferencia (set ())

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

respuesta es set([1])

puede imprimir en forma de lista,

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

i va a echar en ya que ninguna de las presentes soluciones dió 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 no tupla que producen en esta dirección, se preserva el orden

se puede hacer usando el operador XOR pitón.

  • Esto eliminará los duplicados en cada lista
  • Esto mostrará la diferencia de Temp 1 de Temp 2 y Temp 2 de Temp 1.

set(temp1) ^ set(temp2)

Yo quería algo que llevaría dos listas y podría hacer lo que hace diff en bash. Dado que esta cuestión aparece por primera vez cuando se busca "pitón de diferencia de dos listas" y no es muy específico, voy a publicar lo que ocurrió.

SequenceMather de difflib puede comparar dos listas como diff hace. Ninguna de las otras respuestas le indicará la posición en la que se produce la diferencia, pero éste lo hace. Algunas respuestas dan la diferencia en una sola dirección. Algunos reordenar los elementos. Algunos no manejan duplicados. Sin embargo, esta solución le ofrece 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])

Este salidas:

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 que los mismos supuestos las otras respuestas hacen, que se beneficiará de ellos el más. Pero si usted está buscando una verdadera funcionalidad diff, entonces este es el único camino a seguir.

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

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

Sin embargo, esto se hace:

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

Prueba esto:

temp3 = set(temp1) - set(temp2)

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

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

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

Esto es más corta que la de arriba que hace de dos vías diferenciaciones, ya que sólo hace exactamente lo que hace la pregunta:. Generar una lista de lo que hay en la primera lista, pero no el segundo

from collections import Counter

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

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

Por otra parte, en función de sus preferencias de legibilidad, hace que para una sola línea decente:

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

Salida:

['Three', 'Four']

Tenga en cuenta que puede eliminar la llamada list(...) si sólo están interactuando sobre ella.

Debido a que esta solución utiliza los contadores, se maneja adecuadamente cantidades vs 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']

Se puede usar un método ingenuo si los elementos de la difflist se clasifican y conjuntos.

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

print list1[len(list2):]

o con métodos set nativas:

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 Naive: ,0787101593292

solución de conjunto Nativo: ,998837615564

Soy poco demasiado tarde en el juego para esto, pero se puede hacer una comparación de los resultados de algunos de los anteriores código mencionado con esto, dos de los contendientes más rápidos son,

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

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

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

Si se encuentra con TypeError: unhashable type: 'list' lo necesario para convertir las listas o conjuntos en tuplas, por ejemplo.

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

Cómo comparar una lista de listas / juegos en Python?

Aquí están algunos simples, fin de preservación formas de diffing dos listas de cadenas.

Código

Un enfoque inusual usando 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 las dos listas contienen cadenas con inicios equivalentes. Vea la docs para más detalles. Nota, no es especialmente rápido en comparación con las operaciones de configuración.


Una aplicación recta de avance utilizando itertools.zip_longest :

import itertools as it


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

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

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

si desea algo más parecido a un conjunto de cambios ... podría utilizar 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 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 solucionar con una línea. La pregunta se da dos listas (Temp1 y Temp 2) devuelven su diferencia en una tercera lista (TEMP3).

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

Vamos a decir que tenemos dos listas

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

podemos ver de lo anterior dos listas que los artículos 1, 3, 5 existen en list2 y artículos 7, 9 no lo hacen. Por otro lado, los puntos 1, 3, 5 existen en lista1 y los puntos 2, 4 no lo hacen.

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

Todas las respuestas anteriores a encontrar 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

frente

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

El uso de 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')

retornos

[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 su contenido es), se puede obtener el resultado que 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])

Esperamos que esto ayuda.

(list(set(a)-set(b))+list(set(b)-set(a)))
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top