Python: In Liste finden

586

Ich bin auf Folgendes gestoßen:

item = someSortOfSelection()
if item in myList:
    doMySpecialFunction(item)

aber manchmal funktioniert es nicht mit allen meinen Elementen, als ob sie in der Liste nicht erkannt würden (wenn es sich um eine Liste von Zeichenfolgen handelt).

Ist dies die "pythonischste" Art, ein Element in einer Liste zu finden : if x in l:?

Stephane Rolland
quelle
3
Das ist vollkommen in Ordnung und sollte funktionieren, wenn der Gegenstand einem der Elemente im Inneren entspricht myList.
Niklas B.
1
Meinst du, es war der gute Weg, Dinge zu tun? In meinen mehreren Versuchen gab es vielleicht Leerzeichen und Zeilenvorschübe, die sich störten ... Ich wollte nur sichergehen, dass dies der gute Weg ist, "Find in List" (im Allgemeinen) zu implementieren
Stephane Rolland

Antworten:

1174

Was Ihre erste Frage betrifft: Dieser Code ist vollkommen in Ordnung und sollte funktionieren, wenn er itemeinem der darin enthaltenen Elemente entspricht myList. Vielleicht versuchen Sie, eine Zeichenfolge zu finden, die nicht genau mit einem der Elemente übereinstimmt, oder Sie verwenden einen Gleitkommawert, der unter Ungenauigkeit leidet.

Was Ihre zweite Frage betrifft: Es gibt tatsächlich mehrere Möglichkeiten, Dinge in Listen zu "finden".

Überprüfen, ob etwas drin ist

Dies ist der Anwendungsfall, den Sie beschreiben: Überprüfen, ob sich etwas in einer Liste befindet oder nicht. Wie Sie wissen, können Sie den inOperator dafür verwenden:

3 in [1, 2, 3] # => True

Eine Sammlung filtern

Das heißt, alle Elemente in einer Sequenz finden, die eine bestimmte Bedingung erfüllen. Sie können dafür Listenverständnis oder Generatorausdrücke verwenden:

matches = [x for x in lst if fulfills_some_condition(x)]
matches = (x for x in lst if x > 6)

Letzterer gibt einen Generator zurück, den Sie sich als eine Art Lazy List vorstellen können, der erst erstellt wird, wenn Sie ihn durchlaufen. Übrigens ist der erste genau gleichbedeutend mit

matches = filter(fulfills_some_condition, lst)

in Python 2. Hier sehen Sie Funktionen höherer Ordnung bei der Arbeit. Gibt in Python 3 filterkeine Liste zurück, sondern ein generatorähnliches Objekt.

Das erste Vorkommen finden

Wenn Sie nur das erste möchten, das einer Bedingung entspricht (aber Sie wissen noch nicht, was es ist), ist es in Ordnung, eine for-Schleife zu verwenden (möglicherweise auch die elseKlausel, die nicht wirklich bekannt ist). Sie können auch verwenden

next(x for x in lst if ...)

Dies gibt das erste Match zurück oder erhöht ein, StopIterationwenn keines gefunden wird. Alternativ können Sie verwenden

next((x for x in lst if ...), [default value])

Suchen des Standorts eines Elements

Für Listen gibt es auch die indexMethode, die manchmal nützlich sein kann, wenn Sie wissen möchten, wo sich ein bestimmtes Element in der Liste befindet:

[1,2,3].index(2) # => 1
[1,2,3].index(4) # => ValueError

Beachten Sie jedoch, dass bei Duplikaten .indeximmer der niedrigste Index zurückgegeben wird: ......

[1,2,3,2].index(2) # => 1

Wenn es Duplikate gibt und Sie alle Indizes möchten, können Sie enumerate()stattdessen Folgendes verwenden :

[i for i,x in enumerate([1,2,3,2]) if x==2] # => [1, 3]
Niklas B.
quelle
10
Stephane: Lassen Sie es mich umformulieren: Es if x in listist nicht das, worüber sich die Leute beschweren, keine eingebaute Funktion zu sein. Sie beschweren sich über die Tatsache, dass es keinen expliziten Weg gibt, das erste Auftreten von etwas in einer Liste zu finden, das einer bestimmten Bedingung entspricht. Aber wie in meiner Antwort angegeben, next()kann (ab) dafür verwendet werden.
Niklas B.
3
@Stephane: Der zweite generiert kein Tupel, sondern einen Generator (der im Grunde eine noch nicht erstellte Liste ist). Wenn Sie das Ergebnis nur einmal verwenden möchten, ist normalerweise ein Generator vorzuziehen. Wenn Sie die erstellte Sammlung jedoch später mehrmals verwenden möchten, ist es ratsam, zunächst eine explizite Liste zu erstellen. Schauen Sie sich mein Update an, es ist jetzt etwas besser strukturiert :)
Niklas B.
26
Ihr Beispiel "Erstes Auftreten finden" ist golden. Fühlt sich pythonischer an als die [list comprehension...][0]Annäherung
acjay
4
Ich bin immer mehr enttäuscht von Python 'funktionalen' Fähigkeiten. In haskell gibt es im Data.List-Modul eine Suchfunktion, die genau das tut. Aber in Python ist es nicht und es ist zu klein, um es zu einer Bibliothek zu machen, so dass Sie dieselbe Logik immer wieder neu implementieren müssen. Was für eine Verschwendung ...
user1685095
3
Es wäre schön, wenn es ein kwarg, ist index()genannt , keydass wie das funktionierte keydurch akzeptiert max(); zum Beispiel : index(list, key=is_prime).
Curt
189

Wenn Sie ein Element suchen oder Nonedie Standardeinstellung in verwenden möchten next, wird es nicht ausgelöst, StopIterationwenn das Element nicht in der Liste gefunden wurde:

first_or_default = next((x for x in lst if ...), None)
Janusz Skonieczny
quelle
1
nextNimmt einen Iterator als ersten Parameter und eine Liste / ein Tupel ist KEIN Iterator. So soll es werden first_or_default = next(iter([x for x in lst if ...]), None)sehen docs.python.org/3/library/functions.html#next
Devy
7
@Devy: das ist richtig, aber (x for x in lst if ...)ist es, einen Generator über die Liste lst(die ist ein Iterator). Wenn Sie dies tun next(iter([x for x in lst if ...]), None), müssen Sie die Liste [x for x in lst if ...]erstellen, was eine viel teurere Operation ist.
Erlend Graff
1
Hier gibt es eine Abstraktion, um eine Suchfunktion zu definieren. Kapseln Sie einfach die boolesche Expession von ifin ein Lambda und Sie können find(fn,list)normalerweise schreiben, anstatt den Generatorcode zu verschleiern.
Semiomant
22

Während die Antwort von Niklas B. ziemlich umfassend ist, ist es manchmal nützlich, wenn wir ein Element in einer Liste finden möchten, seinen Index zu erhalten:

next((i for i, x in enumerate(lst) if [condition on x]), [default value])
Vincent Cantin
quelle
11

Das erste Vorkommen finden

Dafür gibt es ein Rezept in itertools:

def first_true(iterable, default=False, pred=None):
    """Returns the first true value in the iterable.

    If no true value is found, returns *default*

    If *pred* is not None, returns the first item
    for which pred(item) is true.

    """
    # first_true([a,b,c], x) --> a or b or c or x
    # first_true([a,b], x, f) --> a if f(a) else b if f(b) else x
    return next(filter(pred, iterable), default)

Der folgende Code findet beispielsweise die erste ungerade Zahl in einer Liste:

>>> first_true([2,3,4,5], None, lambda x: x%2==1)
3  
Antony Hatchkins
quelle
6

Eine andere Alternative: Sie können überprüfen, ob sich ein Element in einer Liste mit befindet if item in list:, dies ist jedoch die Reihenfolge O (n). Wenn Sie mit großen Listen von Elementen zu tun haben und nur wissen müssen, ob etwas Mitglied Ihrer Liste ist, können Sie die Liste zuerst in eine Gruppe konvertieren und die Suche nach konstanten Zeitsätzen nutzen :

my_set = set(my_list)
if item in my_set:  # much faster on average than using a list
    # do something

Dies ist nicht in jedem Fall die richtige Lösung, aber in einigen Fällen kann dies zu einer besseren Leistung führen.

Beachten Sie, dass das Erstellen des Sets mit set(my_list)auch O (n) ist. Wenn Sie dies also nur einmal tun müssen, ist es nicht schneller, dies auf diese Weise zu tun. Wenn Sie die Mitgliedschaft jedoch wiederholt überprüfen müssen, ist dies O (1) für jede Suche nach dieser ersten Satzerstellung.

Engineero
quelle
4

Möglicherweise möchten Sie eine von zwei möglichen Suchvorgängen verwenden, während Sie mit einer Liste von Zeichenfolgen arbeiten:

  1. wenn Listenelement gleich ein Element ( ‚Beispiel‘ ist in [ ‚eines‘, ‚Beispiel‘, ‚zwei‘]):

    if item in your_list: some_function_on_true()

    'ex' in ['eins', 'ex', 'zwei'] => True

    'ex_1' in ['eins', 'ex', 'zwei'] => Falsch

  2. Wenn das Listenelement wie ein Element ist ('ex' steht in ['eins,' Beispiel ',' zwei '] oder' Beispiel_1 'steht in [' eins ',' Beispiel ',' zwei ']):

    matches = [el for el in your_list if item in el]

    oder

    matches = [el for el in your_list if el in item]

    dann überprüfen len(matches)oder lesen Sie sie bei Bedarf.

Alexey Antonenko
quelle
3

Definition und Verwendung

Die count()Methode gibt die Anzahl der Elemente mit dem angegebenen Wert zurück.

Syntax

list.count(value)

Beispiel:

fruits = ['apple', 'banana', 'cherry']

x = fruits.count("cherry")

Beispiel der Frage:

item = someSortOfSelection()

if myList.count(item) >= 1 :

    doMySpecialFunction(item)
Josef
quelle
2
Ist das in einer sehr langen Liste effizient? Sagen Sie Liste von einer Million?
3kstc
1
Ich bin mir nicht sicher !!!
Josef
1

Anstatt zu verwenden, list.index(x)welches den Index von x zurückgibt, wenn es in der Liste gefunden wird, oder eine #ValueErrorNachricht zurückgibt , wenn x nicht gefunden wird, können Sie verwenden, list.count(x)welches die Anzahl der Vorkommen von x in der Liste zurückgibt (Bestätigung, dass x tatsächlich in der Liste enthalten ist) oder es Gibt ansonsten 0 zurück (in Abwesenheit von x). Das Coole daran count()ist, dass es Ihren Code nicht kaputt macht oder Sie eine Ausnahme auslösen müssen, wenn x nicht gefunden wird

Taylor
quelle
und das schlechte ist, dass es Elemente zählt . Es hört nicht auf, wenn ein Element gefunden wird. Daher ist die Leistung auf großen Listen schlecht
Jean-François Fabre
1

Wenn Sie einmal prüfen möchten, ob der Wert im Sammlerstück vorhanden ist, ist die Verwendung des Operators 'in' in Ordnung. Wenn Sie jedoch mehrmals prüfen möchten, empfehle ich die Verwendung des Halbierungsmoduls. Beachten Sie, dass die Daten des Halbierungsmoduls sortiert werden müssen. Sie sortieren die Daten also einmal und können dann die Halbierung verwenden. Die Verwendung des Halbierungsmoduls auf meinem Computer ist ungefähr 12-mal schneller als die Verwendung des In-Operators.

Hier ist ein Beispiel für Code mit Python 3.8 und höher:

import bisect
from timeit import timeit

def bisect_search(container, value):
    return (
      (index := bisect.bisect_left(container, value)) < len(container) 
      and container[index] == value
    )

data = list(range(1000))
# value to search
true_value = 666
false_value = 66666

# times to test
ttt = 1000

print(f"{bisect_search(data, true_value)=} {bisect_search(data, false_value)=}")

t1 = timeit(lambda: true_value in data, number=ttt)
t2 = timeit(lambda: bisect_search(data, true_value), number=ttt)

print("Performance:", f"{t1=:.4f}, {t2=:.4f}, diffs {t1/t2=:.2f}")

Ausgabe:

bisect_search(data, true_value)=True bisect_search(data, false_value)=False
Performance: t1=0.0220, t2=0.0019, diffs t1/t2=11.71
Vlad Bezden
quelle
0

Stellen Sie sicher, dass in den Elementen der Liste der Zeichenfolgen kein zusätzlicher / unerwünschter weißer Speicherplatz vorhanden ist. Dies ist ein Grund, der die Erklärung der Elemente stören kann.

Stephane Rolland
quelle