Question

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

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

Je dois créer une troisième liste des articles 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?

Était-ce utile?

La solution

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

Garde-toi

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

où vous pourriez attendre / veulent à égale set([1, 3]). Si vous ne voulez set([1, 3]) que votre réponse, vous aurez besoin d'utiliser set([1, 2]).symmetric_difference(set([2, 3])).

Autres conseils

Les solutions existantes offrent toutes un ou l'autre de:

  • Plus rapide que O (n * m) performance.
  • Preserve ordre de la liste d'entrée.

Mais jusqu'à présent, aucune solution n'a à la fois. Si vous voulez à la fois, 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 je présentais ainsi que pour la conservation est aussi (un peu) plus vite que la soustraction de jeu, car il ne nécessite pas la construction d'un ensemble inutile. La différence de performance serait plus si la première noticable liste est beaucoup plus longue que la seconde et si le hachage est cher. Voici un second 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
temp3 = [item for item in temp1 if item not in temp2]

La différence entre les deux listes (par exemple 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 donnera le résultat ['Four', 'Three']. Vous n'avez pas à vous soucier de l'ordre de la liste ou dont la liste doit être donnée d'abord.

référence doc Python

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

Installation

Installer à partir PyPI:

pip install deepdiff

Exemple d'utilisation

Importer

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

objet retourne même vide

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

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

Point ajouté et / ou enlevé

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

Chaîne différence 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 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 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 qui contient le 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]']}

Nommé Tuples:

>>> 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 Object ajouté:

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

Si vous êtes à la recherche vraiment dans la performance, utilisez numpy!

Voici le bloc-notes complet comme essentiel sur github avec une comparaison entre la liste, numpy et pandas géants.

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

 entrer image description ici

moyen le plus simple,

Utilisation différence set (). (Set ())

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

réponse est set([1])

peut imprimer une liste,

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

Je vais jeter dans la mesure où aucun des solutions actuelles donner 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 les autres non-réponses tuple donnant dans ce sens, il préserve

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

  • Ceci supprimer les doublons dans chaque liste
  • Cela montre la différence de temp1 de temp2 et temp2 de temp1.

set(temp1) ^ set(temp2)

Je voulais quelque chose qui prendrait deux listes et pourrait faire ce diff dans bash fait. Étant donné que cette question apparaît d'abord lorsque vous effectuez une recherche pour « python diff deux listes » et n'est pas très précis, je vais poster ce que je suis venu avec.

Utilisation SequenceMather de difflib vous pouvez comparer deux listes comme diff fait. Aucun des autres réponses vous indiquera la position où la différence se produit, mais celui-ci fait. Certaines réponses donnent la différence dans une seule direction. Certains réordonner les éléments. Certains ne traitent pas de doublons. Mais cette solution vous donne une vraie différence entre les deux listes:

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

sorties:

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

Bien sûr, si votre application fait les mêmes hypothèses les autres réponses font, vous en bénéficier le plus. Mais si vous êtes à la recherche d'une véritable fonctionnalité diff, alors c'est le seul chemin à parcourir.

Par exemple, aucun des autres réponses pourrait gérer:

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

Mais celui-ci fait:

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

Essayez ceci:

temp3 = set(temp1) - set(temp2)

cela pourrait être encore plus rapide que la compréhension de la liste de Marc:

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

Voici une réponse Counter pour le cas le plus simple.

est plus courte que celle ci-dessus qui ne diffs dans les deux sens, car il ne fait que exactement ce que la question demande:. Générer une liste de ce qui est dans la première liste, mais pas la seconde

from collections import Counter

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

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

Vous pouvez également, en fonction de vos préférences de lisibilité, il en fait un one-liner décent:

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

Sortie:

['Three', 'Four']

Notez que vous pouvez supprimer l'appel list(...) si vous êtes itère dessus.

Parce que cette solution utilise des compteurs, il gère des quantités correctement contre les nombreuses réponses basées sur des ensembles. Par exemple sur cette entrée:

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

La sortie est:

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

Vous pouvez utiliser une méthode naïve si les éléments du difflist sont triées et ensembles.

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

print list1[len(list2):]

ou avec des méthodes de réglage natives:

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)

solution Naive: ,0787101593292

solution ensemble native: ,998837615564

Je suis peu trop tard dans le jeu pour cela, mais vous pouvez faire une comparaison des performances de certains des code ci-dessus mentionné avec cela, deux des prétendants les plus rapides sont,

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

Je présente mes excuses pour le niveau élémentaire de codage.

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

Ceci est une autre solution:

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 vous rencontrez TypeError: unhashable type: 'list' vous devez activer des listes ou des ensembles en tuples, par exemple.

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

Voir aussi Comment comparer une liste des listes / jeux en python?

Voici quelques simples, -maintien de l'ordre façons de diffing deux listes de chaînes.

code

Une approche inhabituelle en utilisant 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']

Cela suppose contiennent les deux listes de chaînes avec des débuts équivalents. Voir la docs pour plus de détails. Remarque, il est particulièrement rapide par rapport aux opérations set.


Une mise en œuvre straight-forward en utilisant itertools.zip_longest :

import itertools as it


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

version unique ligne de arulmr solution

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

si vous voulez quelque chose de plus comme un ... changeset pourrait utiliser contre

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"

On peut calculer l'intersection union moins des listes:

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

set(temp1+temp2)-(set(temp1)&set(temp2))

Out: set(['Four', 'Five', 'Three']) 

Ceci peut être résolu avec une seule ligne. La question est donnée deux listes (TEMP1 et TEMP2) renvoient leur différence dans une troisième liste (temp3).

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

Le mot Let nous avons deux listes

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

nous pouvons voir de ce qui précède deux listes que les articles 1, 3, 5 existons dans liste2 et des articles 7, 9 ne le font pas. D'autre part, les articles 1, 3, 5 et existons dans list1 articles 2, 4 ne sont pas.

Quelle est la meilleure solution pour retourner une nouvelle liste contenant des articles 7, 9 et 2, 4?

Toutes les réponses ci-dessus trouver la solution, ce qui est maintenant la plus optimale?

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

contre

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

En utilisant timeit nous pouvons voir les résultats

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

retourne

[7, 9, 2, 4]
Using two for loops 0.11572412995155901 Milliseconds
Using symmetric_difference 0.11285737506113946 Milliseconds

Process finished with exit code 0

Voici un moyen simple de distinguer deux listes (quel que soit le contenu sont), vous pouvez obtenir le résultat comme indiqué ci-dessous:

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

Espérons que cela utile.

(list(set(a)-set(b))+list(set(b)-set(a)))
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top