621 Stimmen

Alle Elemente, die in einer Liste vorkommen, aus einer anderen entfernen

Nehmen wir an, ich habe zwei Listen, l1 y l2 . Ich möchte auftreten l1 - l2 die alle Elemente von l1 nicht in l2 .

Ich kann mir eine naive Schleifenlösung vorstellen, aber das wäre wirklich ineffizient. Was ist ein pythonischer und effizienter Weg, dies zu tun?

Ein Beispiel: Wenn ich l1 = [1,2,6,8] and l2 = [2,3,5,8] , l1 - l2 sollte zurückkehren [1,6]

28 Stimmen

Nur ein Tipp: PEP8 besagt, dass das kleine "L" nicht verwendet werden sollte, weil es zu sehr wie eine 1 aussieht.

3 Stimmen

Ich stimme zu. Ich habe diese ganze Frage und die Antworten gelesen und mich gefragt, warum die Leute immer wieder elf und zwölf verwenden. Erst als ich den Kommentar von @spelchekr las, ergab es einen Sinn.

1 Stimmen

13voto

lbsweek Punkte 4546

Verwenden. Mengenkomplexe {x für x in l2} oder set(l2), um set zu erhalten, dann verwenden Sie Auflistung von Zusammenfassungen um die Liste zu erhalten

l2set = set(l2)
l3 = [x for x in l1 if x not in l2set]

Benchmark-Testcode:

import time

l1 = list(range(1000*10 * 3))
l2 = list(range(1000*10 * 2))

l2set = {x for x in l2}

tic = time.time()
l3 = [x for x in l1 if x not in l2set]
toc = time.time()
diffset = toc-tic
print(diffset)

tic = time.time()
l3 = [x for x in l1 if x not in l2]
toc = time.time()
difflist = toc-tic
print(difflist)

print("speedup %fx"%(difflist/diffset))

Ergebnis des Benchmark-Tests:

0.0015058517456054688
3.968189239501953
speedup 2635.179227x

8voto

Akshay Hazari Punkte 3005

Alternative Lösung :

reduce(lambda x,y : filter(lambda z: z!=y,x) ,[2,3,5,8],[1,2,6,8])

8voto

Moinuddin Quadri Punkte 43207

使用する set.difference() :

Sie können verwenden set.difference() um eine neue Menge zu erhalten, die Elemente enthält, die in den anderen Mengen nicht enthalten sind, d. h. set(A).difference(B) gibt ein Set mit Elementen zurück, die in A , aber nicht in B . Zum Beispiel:

>>> set([1,2,6,8]).difference([2,3,5,8])
{1, 6}

Es ist ein funktionalen Ansatz zu erhalten set Unterschied erwähnt in Arkku's Antwort (die arithmetische Subtraktion verwendet - Operator für Differenzmengen) .

Desde setzt nicht geordnet sind, verlieren Sie die Reihenfolge der Elemente der ursprünglichen Liste. (lesen Sie den nächsten Abschnitt weiter, wenn Sie die Reihenfolge der Elemente beibehalten wollen)

使用する Liste Verstehen con set basiertes Nachschlagen

Wenn Sie wollen um die Reihenfolge der ursprünglichen Liste beizubehalten entonces Verständnis der Liste von Donut basierte Antwort wird den Zweck erfüllen. Sie können jedoch eine bessere Leistung erzielen aus der akzeptierten Antwort durch die Verwendung von set intern um zu prüfen, ob ein Element in einer anderen Liste vorhanden ist. Zum Beispiel:

l1, l2 = [1,2,6,8], [2,3,5,8]
s2 = set(l2)  # Type-cast `l2` to `set`

l3 = [x for x in l1 if x not in s2]
                             #   ^ Doing membership checking on `set` s2

Wenn Sie wissen möchten, warum die Überprüfung der Mitgliedschaft schneller ist set im Vergleich zu list dann lesen Sie bitte dies: Was macht Sets schneller als Listen?


使用する filter() y Lambda-Ausdruck

Hier ist eine weitere alternative Verwendung filter() を持っています。 Lambda-Ausdruck . Ich füge sie hier nur als Referenz ein, aber sie ist nicht leistungsfähig:

>>> l1 = [1,2,6,8]
>>> l2 = set([2,3,5,8])

#     v  `filter` returns the a iterator object. Here I'm type-casting 
#     v  it to `list` in order to display the resultant value
>>> list(filter(lambda x: x not in l2, l1))
[1, 6]

5voto

Sebastian Baltser Punkte 579

使用する filterfalse ohne lambda-Ausdruck

Bei der Verwendung von Funktionen wie filter o filterfalse und ähnliches aus itertools können Sie in der Regel Leistung sparen, indem Sie die lambda -Ausdrücke und die Verwendung bereits vorhandener Funktionen. Instanzen von list y set definiert eine __contains__ -Methode, die für Einschließungsprüfungen zu verwenden ist. Die in -Operator ruft diese Methode unter der Haube auf, so dass die Verwendung von x in l2 kann ersetzt werden durch l2.__contains__(x) . Normalerweise ist dieser Ersatz nicht wirklich schöner, aber in diesem speziellen Fall ermöglicht er uns eine bessere Leistung als die Verwendung einer lambda -Ausdruck, wenn er in Kombination mit filterfalse :

>>> from itertools import filterfalse
>>> l1 = [1, 2, 6, 8]
>>> l2 = [2, 3, 5, 8]
>>> list(filterfalse(l2.__contains__, l1))
[1, 6]

filterfalse erzeugt einen Iterator, der alle Elemente liefert, die false bei Verwendung als Argument für l2.__contains__ .

Sets hat eine schnellere Implementierung von __contains__ also noch besser ist:

>>> from itertools import filterfalse
>>> l1 = [1, 2, 6, 8]
>>> l2 = set([2, 3, 5, 8])
>>> list(filterfalse(l2.__contains__, l1))
[1, 6]

Leistung

Liste verwenden:

$  python3 -m timeit -s "from itertools import filterfalse; l1 = [1,2,6,8]; l2 = set([2,3,5,8]);" "list(filterfalse(l2.__contains__, l1))"
500000 loops, best of 5: 522 nsec per loop

Set verwenden:

$ python3 -m timeit -s "from itertools import filterfalse; l1 = [1,2,6,8]; l2 = set([2,3,5,8]);" "list(filterfalse(l2.__contains__, l1))"
1000000 loops, best of 5: 359 nsec per loop

2voto

Deepak Gaur Punkte 68

Der festgelegte Ansatz ist der beste, wenn Sie DIESES Verhalten WOLLEN. Wenn Sie nicht alle Instanzen von Elementen in der Liste l1 entfernen wollen, die nur einmal in l2 vorkommen, führen diese Mengenoperationen zu falschen Ergebnissen. Angenommen, Sie haben sich wiederholende Elemente in l1 und wahrscheinlich auch in l2 und wollen eine tatsächliche Differenz der beiden Listen l1 - l2, wobei die Reihenfolge der verbleibenden Elemente beibehalten wird:

l1 = [1, 2, 3, 4, 5, 5, 6, 5, 5, 2]
l2 = [1, 2, 2, 5]
_ = [l1.remove(item) for item in l2 if item in l1] # discard return value
print(l1) # [3, 4, 5, 6, 5, 5]
  1. Beachten Sie, dass dies deutlich langsamer ist als der Set-Betrieb. Verwenden Sie dies nur, wenn Ihr Anwendungsfall es erfordert.
  2. Wenn Sie die ursprüngliche Liste nicht ändern wollen, erstellen Sie zunächst eine Kopie der Liste.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X