Frage

Ich habe zwei Listen in Python, wie diese:

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

Ich brauche eine dritte Liste mit Elementen aus der ersten Liste zu erstellen, die in dem zweiten nicht vorhanden sind. Aus dem Beispiel habe ich zu bekommen:

temp3 = ['Three', 'Four']

Gibt es schnelle Wege ohne Zyklen und Kontrolle?

War es hilfreich?

Lösung

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

Beachten Sie, dass

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

, wo man erwarten könnte / möchte es gleich set([1, 3]). Wenn Sie möchten, set([1, 3]) als Antwort tun, werden Sie zur Verwendung set([1, 2]).symmetric_difference(set([2, 3])) benötigen.

Andere Tipps

Die bestehenden Lösungen bieten alle entweder das eine oder das andere von:

  • Schneller als O (n * m) Leistung.
  • Preserve Reihenfolge der Eingabeliste.

Aber bisher hat keine Lösung beide. Wenn Sie beide wollen, versuchen Sie dies:

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

Leistungstest

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)

Ergebnisse:

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

Die Methode, die ich als gut präsentiert als um die Erhaltung ist auch (geringfügig) schneller als die eingestellte Subtraktion, weil es nicht erforderlich Bau eines unnötigen Satzes. Der Performance-Unterschied wäre noticable wenn die erste Liste ist wesentlich länger als die zweiten und wenn Hashing ist teuer. Hier ist ein zweiter Test demonstriert dies:

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

Ergebnisse:

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]

Der Unterschied zwischen zwei Listen (etwa list1 und list2) kann mit der folgenden einfachen Funktion gefunden werden.

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)

oder

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

Durch die obige Funktion kann die Differenz gefunden diff(temp2, temp1) oder diff(temp1, temp2) verwendet werden. Beide werden das Ergebnis ['Four', 'Three'] geben. Sie haben keine Sorgen zu machen über die Reihenfolge der Liste oder welche Liste zuerst gegeben werden.

Python doc Referenz

Falls Sie den Unterschied rekursiv wollen, habe ich ein Paket für Python geschrieben: https://github.com/seperman/deepdiff

Installation

Installieren

von PyPI:

pip install deepdiff

Beispiel für die Verwendung

Importieren

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

Die gleiche Objekt kehrt leer

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

Typ eines Artikels hat sich geändert

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

Wert eines Artikels hat sich geändert

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

Element hinzugefügt und / oder entfernt

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

String Differenz

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

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

Geben Sie change

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

>>> 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 Differenz 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 Unterschied ignoriert Ordnung oder Duplikate: (mit den gleichen Wörterbücher wie oben)

>>> 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, die Wörterbuch enthält:

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

Named Tupeln:

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

Benutzerdefinierte Objekte:

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

Objekt Attribut hinzugefügt:

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

Wenn Sie wirklich in Leistung suchen, dann verwenden numpy!

Hier ist die vollständige Notebook als Kern auf Github mit Vergleich zwischen Liste, numpy und Pandas.

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

 image description hier

eingeben

einfachste Art und Weise,

Verwendung set (). Differenz (set ())

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

Antwort ist set([1])

als eine Liste drucken,

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

Ich werde in werfen, da keines der vorliegenden Lösungen ergibt ein Tupel:

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

alternativ:

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

Wie die anderen Nicht-Tupel ergibt Antworten in dieser Richtung, bewahrt es um

Kann mit Python XOR-Operator erfolgen.

  • Dadurch wird die Duplikate in jeder Liste
  • entfernen
  • Dies wird Unterschied von temp1 von temp2 zeigen und TEMP2 von temp1.

set(temp1) ^ set(temp2)

wollte ich etwas, das zwei Listen nehmen würde und könnte tun, was diff in bash tut. Da diese Frage zuerst erscheint, wenn Sie für „Python diff zwei Listen“ suchen und sind nicht sehr spezifisch, werde ich schreiben, was ich kam mit.

Mit SequenceMather von difflib können Sie zwei Listen vergleichen wie diff tut. Keiner der anderen Antworten werden Sie die Position sagen, wo der Unterschied auftritt, aber dies tut. Einige Antworten geben den Unterschied in nur eine Richtung. Einige neu ordnen die Elemente. Einige behandeln keine Duplikate. Aber diese Lösung gibt Ihnen einen wahren Unterschied zwischen zwei Listen:

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

Diese Ausgänge:

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

Natürlich, wenn Ihre Anwendung die gleichen Annahmen die anderen Antworten macht machen, werden Sie von ihnen am meisten profitieren. Aber wenn Sie sich für eine echte diff Funktionalität suchen, dann ist dies der einzige Weg zu gehen.

Zum Beispiel keines der anderen Antworten könnte behandeln:

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

Aber das tut:

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

Versuchen Sie diese:

temp3 = set(temp1) - set(temp2)

könnte dies schneller sein, auch als Mark Liste Verständnis:

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

Hier ist eine Counter Antwort für den einfachsten Fall.

Dies ist kürzer als die oben das tut Zweiwegevergleich, weil es nur genau das tut, was die Frage stellt:. Eine Liste erzeugen, was in der ersten Liste ist aber nicht die zweite

from collections import Counter

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

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

Alternativ, je nach Ihren Vorlieben Lesbarkeit, macht es für einen anständigen Einzeiler:

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

Ausgabe:

['Three', 'Four']

Beachten Sie, dass Sie den list(...) Anruf entfernen können, wenn Sie nur über sie iterieren.

Da diese Lösung Zähler verwendet, behandelt es Mengen richtig gegen die viele Set-basierten Antworten. Zum Beispiel an diesem Eingang:

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

Die Ausgabe lautet:

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

Sie könnten eine naive Methode verwenden, wenn die Elemente des difflist sortieren und Sets.

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

print list1[len(list2):]

oder mit nativen Set-Methoden:

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)

Naive Lösung: ,0787101593292

Native Set Lösung: ,998837615564

Ich bin etwas zu spät im Spiel für diese, aber Sie können mit diesem einen Vergleich der Leistung von einigen der oben genannten Code zu tun, zwei der am schnellsten Anwärter sind,

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

Ich entschuldige mich für die Grundstufe der Codierung.

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

Dies ist eine weitere Lösung:

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

Wenn Sie in TypeError: unhashable type: 'list' ausführen müssen Sie Listen oder Sätze in Tupeln drehen, z.

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

Siehe auch Wie eine Liste von Listen vergleichen / Sätze in python?

Hier sind ein paar einfache, ordnungserhalt Weisen diffing zwei Listen von Strings.

Code

Ein ungewöhnlicher Ansatz 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']

Dies setzt voraus, beide Listen Strings mit gleichwertigen Anfänge enthalten. Sehen Sie sich die docs für weitere Details. Beachten Sie, es ist nicht besonders schnell im Vergleich zu Mengenoperationen.


Eine Straight-Forward-Implementierung unter Verwendung von itertools.zip_longest :

import itertools as it


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

Einzelzeilen-Version von arulmr Lösung

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

Wenn Sie etwas mehr wie ein changeset wollen ... könnte Zähler verwenden

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"

Wir können Kreuzung minus Vereinigung von Listen berechnen:

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

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

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

Dies kann mit einer Zeile gelöst werden. Die Frage ist gegeben zwei Listen (TEMP1 und TEMP2) zurückkehren, um ihre Differenz in einer dritten Liste (temp3).

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

Lassen Sie uns sagen, wir haben zwei Listen

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

können wir aus den beiden oben genannten Listen sehen, dass Artikel 1, 3, 5 exist in list2 und Artikel 7, 9 nicht. Auf der anderen Seite, Artikel 1, 3, 5 exist in list1 und Artikel 2, 4 nicht.

Was ist die beste Lösung, um eine neue Liste Rückholeinzelteile mit 7, 9 und 2, 4?

Alle Antworten über die Lösung finden, jetzt was das optimalste?

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

Vergleich

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

Mit timeit können wir die Ergebnisse sehen

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

Rückkehr

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

Process finished with exit code 0

Dies ist eine einfache Möglichkeit, zwei Listen zu unterscheiden (was auch immer der Inhalt), können Sie das Ergebnis erhalten, wie unten dargestellt:

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

hoffen, dass dies hilfreich.

(list(set(a)-set(b))+list(set(b)-set(a)))
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top