Question Obtenez la différence entre deux listes


J'ai deux listes en Python, comme celles-ci:

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

J'ai besoin de créer une troisième liste avec des éléments de la première liste qui ne sont pas présents dans le second. De l'exemple que je dois obtenir:

temp3 = ['Three', 'Four']

Y a-t-il des moyens rapides sans cycles et vérification?


508
2017-08-11 19:38


origine


Réponses:


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

Méfiez-vous que

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

où vous pouvez vous attendre / voulez que ce soit égal set([1, 3]). Si tu veux set([1, 3]) comme réponse, vous devrez utiliser set([1, 2]).symmetric_difference(set([2, 3])).


794
2017-08-11 19:40



Les solutions existantes offrent toutes l'une ou l'autre:

  • Plus rapide que les performances O (n * m).
  • Conserver l'ordre de la liste d'entrée.

Mais jusqu'à présent, aucune solution n'a les deux. Si vous voulez les deux, essayez ceci:

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

Test de performance

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)

Résultats:

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

La méthode que j'ai présentée ainsi que la préservation de l'ordre sont également (légèrement) plus rapides que la soustraction, car elles ne nécessitent pas la construction d'un ensemble inutile. La différence de performance serait plus perceptible si la première liste est considérablement plus longue que la seconde et si le hachage est cher. Voici un deuxième test démontrant ceci:

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

Résultats:

11.3836875916 # ars' answer
3.63890368748 # this answer (3 times faster!)
37.7445402279 # matt b's answer

386
2017-08-11 19:44



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

49
2017-08-11 19:40



Si vous voulez la différence récursivement, j'ai écrit un paquet pour python: https://github.com/seperman/deepdiff

Installation

Installer à partir de PyPi:

pip install deepdiff

Exemple d'utilisation

Importation

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

Le même objet retourne vide

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

Le type d'un élément a changé

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

La valeur d'un élément a changé

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

Article ajouté et / ou supprimé

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

Différence de chaîne

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

Différence de cordes 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

Changement de type

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

Liste de différence

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

Liste différence 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}}}

Liste différence en ignorant l'ordre ou les doublons: (avec les mêmes dictionnaires que ci-dessus)

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

Liste contenant un dictionnaire:

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

Ensembles:

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

Tuples nommés:

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

Objets personnalisés:

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

Attribut d'objet ajouté:

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

16
2017-09-27 21:30



La différence entre deux listes (disons list1 et list2) peut être trouvée en utilisant la fonction simple suivante.

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)

ou

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

En utilisant la fonction ci-dessus, la différence peut être trouvée en utilisant diff(temp2, temp1) ou diff(temp1, temp2). Les deux donneront le résultat ['Four', 'Three']. Vous n'avez pas à vous soucier de l'ordre de la liste ou de la liste à donner en premier.

Référence doc Python


15
2017-08-17 11:38



Si vous regardez vraiment dans la performance, alors utilisez numpy!

Voici le cahier complet sur Github avec une comparaison entre liste, numpy et pandas.

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

enter image description here


14
2017-08-07 15:30



Je vais le faire car aucune des solutions actuelles ne donne un tuple:

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

alternativement:

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

Comme l'autre non-tuple donnant des réponses dans cette direction, il préserve l'ordre


12
2017-08-11 19:42



Peut être fait en utilisant l'opérateur python XOR.

  • Cela supprimera les doublons dans chaque liste
  • Cela montrera la différence de temp1 de temp2 et temp2 de temp1.

set(temp1) ^ set(temp2)

11
2017-07-07 07:50