Überprüfen Sie, ob etwas in einer Liste in Python (nicht) enthalten ist

314

Ich habe eine Liste von Tupeln in Python und eine Bedingung, unter der ich den Zweig NUR nehmen möchte, wenn das Tupel nicht in der Liste enthalten ist (wenn es in der Liste enthalten ist, möchte ich den Zweig if nicht verwenden).

if curr_x -1 > 0 and (curr_x-1 , curr_y) not in myList: 

    # Do Something

Das funktioniert bei mir allerdings nicht wirklich. Was habe ich falsch gemacht?

Zack
quelle
1
Beachten Sie, dass 3 -1 > 0 and (4-1 , 5) not in []Trueder Fehler daher keine Priorität für den Operator hat.
Dan D.
6
Was meinst du mit "nicht wirklich für mich arbeiten"? Was erwartest du? Was passiert eigentlich? Welche genauen Listeninhalte lösen das Problem aus?
Karl Knechtel
Warum nicht versuchen myList.count((curr_x, curr_y)), wenn (curr_x, curr_y)nicht in myList, wird das Ergebnis sein0
LittleLittleQ
2
Wie hat diese Frage "Mein Code funktioniert nicht wirklich für mich" 297 positive Stimmen erhalten? Bitte geben Sie uns ein minimal reproduzierbares Beispiel .
Gerrit

Antworten:

503

Der Fehler befindet sich wahrscheinlich an einer anderen Stelle in Ihrem Code, da er einwandfrei funktionieren sollte:

>>> 3 not in [2, 3, 4]
False
>>> 3 not in [4, 5, 6]
True

Oder mit Tupeln:

>>> (2, 3) not in [(2, 3), (5, 6), (9, 1)]
False
>>> (2, 3) not in [(2, 7), (7, 3), "hi"]
True
orlp
quelle
11
@ Zack: Wenn Sie nicht darüber wüssten, könnten Sie einfach tunif not ELEMENT in COLLECTION:
Ninjagecko
@ninjagecko: Je nach Containertyp kann dies weniger effizient oder sogar falsch sein. Siehe zum Beispiel Bloom-Filter .
Orlp
14
@nightcracker Das macht keinen Sinn, da A not in Bes auf das reduziert ist, not B.__contains__(A)was das gleiche ist wie das, was auf not A in Bdas reduziert ist not B.__contains__(A).
Dan D.
1
Oh wow, ich hätte schwören können, dass Python so etwas hatte __notcontains__. Es tut mir leid, dann ist das, was ich gesagt habe, nur Schwachsinn.
Orlp
2
@ std''OrgnlDave Der einzige Weg, der passieren könnte, wäre, wenn er noteine höhere Priorität hätte als indies nicht der Fall ist. Betrachten Sie das Ergebnis, ast.dump(ast.parse("not A in B").body[0])das zu "Expr(value=UnaryOp(op=Not(), operand=Compare(left=Name(id='A', ctx=Load()), ops=[In()], comparators=[Name(id='B', ctx=Load())])))"Wenn Sie noteng zu A gruppiert sind, hätte man erwartet, dass das Ergebnis "Expr(value=Compare(left=UnaryOp(op=Not(), operand=Name(id='A', ctx=Load())), ops=[In()], comparators=[Name(id='B', ctx=Load())]))"das ist, für das analysiert wird "(not A) in B".
Dan D.
20

Wie überprüfe ich, ob etwas in einer Liste in Python (nicht) enthalten ist?

Die billigste und am besten lesbare Lösung ist die Verwendung des inOperators (oder in Ihrem speziellen Fall not in). Wie in der Dokumentation erwähnt,

Die Betreiber inund not inTest auf Mitgliedschaft. x in sbewertet, Trueob xMitglied von ists und Falseanderweitig ist. x not in sgibt die Negation von zurück x in s.

Zusätzlich,

Der Betreiber not in hat den umgekehrten wahren Wert von in.

y not in xist logisch das gleiche wie not y in x.

Hier einige Beispiele:

'a' in [1, 2, 3]
# False

'c' in ['a', 'b', 'c']
# True

'a' not in [1, 2, 3]
# True

'c' not in ['a', 'b', 'c']
# False

Dies funktioniert auch mit Tupeln, da Tupel hashbar sind (aufgrund der Tatsache, dass sie auch unveränderlich sind):

(1, 2) in [(3, 4), (1, 2)]
#  True

Wenn das Objekt auf der RHS eine __contains__()Methode definiert , inwird es intern aufgerufen, wie im letzten Absatz des Abschnitts " Vergleiche " der Dokumente angegeben.

... inund not inwerden von Typen unterstützt, die iterierbar sind oder die __contains__()Methode implementieren . Zum Beispiel könnten (aber sollten) Sie dies nicht tun:

[3, 2, 1].__contains__(1)
# True

inKurzschlüsse. Wenn sich Ihr Element also am Anfang der Liste befindet, wird es inschneller ausgewertet:

lst = list(range(10001))
%timeit 1 in lst
%timeit 10000 in lst  # Expected to take longer time.

68.9 ns ± 0.613 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
178 µs ± 5.01 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Wenn Sie mehr als nur prüfen möchten, ob sich ein Element in einer Liste befindet, gibt es folgende Optionen:

  • list.indexkann verwendet werden, um den Index eines Elements abzurufen. Wenn dieses Element nicht vorhanden ist, ValueErrorwird a ausgelöst.
  • list.count kann verwendet werden, wenn Sie die Vorkommen zählen möchten.

Das XY-Problem: Haben Sie darüber nachgedacht? set s ?

Stellen Sie sich folgende Fragen:

  • Müssen Sie mehrmals prüfen, ob ein Element in einer Liste enthalten ist?
  • Wird diese Prüfung in einer Schleife durchgeführt oder eine Funktion wiederholt aufgerufen?
  • Sind die Elemente, die Sie auf Ihrer Liste speichern, hashbar? IOW, können Sie sie anrufen hash?

Wenn Sie diese Fragen mit "Ja" beantwortet haben, sollten Sie setstattdessen ein verwenden. Einin Mitgliedschaftstest für lists ist O (n) Zeitkomplexität. Dies bedeutet, dass Python einen linearen Scan Ihrer Liste durchführen muss, jedes Element besucht und es mit dem Suchelement vergleicht. Wenn Sie dies wiederholt tun oder wenn die Listen groß sind, verursacht dieser Vorgang einen Overhead.

setObjekte hingegen haben ihre Werte für die Überprüfung der Mitgliedschaft in konstanter Zeit gehasht. Die Überprüfung erfolgt auch mit in:

1 in {1, 2, 3} 
# True

'a' not in {'a', 'b', 'c'}
# False

(1, 2) in {('a', 'c'), (1, 2)}
# True

Wenn Sie das Pech haben, dass das Element, nach dem Sie suchen / nicht suchen, am Ende Ihrer Liste steht, hat Python die Liste bis zum Ende gescannt. Dies geht aus den folgenden Zeitpunkten hervor:

l = list(range(100001))
s = set(l)

%timeit 100000 in l
%timeit 100000 in s

2.58 ms ± 58.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
101 ns ± 9.53 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

Zur Erinnerung, dies ist eine geeignete Option, solange die Elemente, die Sie speichern und nachschlagen, hashbar sind. IOW müssten entweder unveränderliche Typen oder implementierte Objekte sein __hash__.

cs95
quelle
2
Sets sind nicht immer eine Option (z. B. wenn eine Liste veränderbarer Elemente vorhanden ist). Für große Sammlungen: Das Erstellen des Sets für eine Suche ist ohnehin O (n) und kann die Speichernutzung verdoppeln. Wenn Sie sich noch nicht umgesehen haben, ist es nicht immer die beste Wahl, eine zu erstellen / zu pflegen.
wim