list.index () -Funktion für Python, die keine Ausnahme auslöst, wenn nichts gefunden wird

76

Python list.index(x)löst eine Ausnahme aus, wenn das Element nicht vorhanden ist. Gibt es einen besseren Weg, um Ausnahmen zu behandeln?

Yarin
quelle
1
Hängt davon ab. Interessiert es dich, wo es ist?
Ignacio Vazquez-Abrams
2
Der beste Weg, dies zu tun, hängt davon ab, was Sie tun, wenn nichts gefunden wird. Selbst wenn wir list.find hätten , das eine -1 zurückgibt , müssten Sie immer noch testen, ob die i == -1und etwas unternehmen.
Raymond Hettinger
2
Raymond - es scheint nur an mir zu liegen, zu entscheiden, ob mein Code keine Indizes verarbeiten kann, anstatt die Ausnahme zu erzwingen. Aber dann lerne ich immer noch, wie man pythonisch ist ...
Yarin
@yarin, wie ich in meiner Antwort klargestellt habe: Wenn Sie den Index nicht benötigen, ist das inSchlüsselwort genau das, was Sie brauchen. Aber wenn Sie das tun, hat Raymond meiner Meinung nach einen guten Punkt, und Ausnahmen sind der beste Weg, dies zu erreichen.
Nealmcb

Antworten:

93

Wenn es Ihnen egal ist, wo sich das passende Element befindet, verwenden Sie:

found = x in somelist

Wenn Sie sich interessieren, verwenden Sie einen LBYL- Stil mit einem bedingten Ausdruck :

i = somelist.index(x) if x in somelist else None
Raymond Hettinger
quelle
2
Vielen Dank, Raymond, fand dies die prägnanteste Antwort (Wiederum wurde die Standardeinstellung von -1 in Keine geändert, da -1 ein gültiger Listenindex ist)
Yarin
1
Danke Raymond, LBYL war eine neue Referenz für mich.
Burhan Khalid
14
Aber ist dieser Ansatz nicht viel langsamer als beim Laufen index()? Immerhin muss man zweimal suchen: einmal nach der Existenz und einmal nach dem Index. Aus diesem Grund ist C ++ Container nicht ein haben exists(), nur find().
Frans
9
Wie @frans sagte, erfordert dies zwei Suchvorgänge, aber hier ist eine andere Möglichkeit, die Arbeit in einem Durchgang zu i = next((i for i, t in enumerate(somelist) if x == t), None)
erledigen
@AXO Obwohl es sich um einen Durchgang handelt, wird es für integrierte Typen langsamer, da die Suche eher von Python als von C-Code durchgeführt wird.
ivan_pozdeev
7

eigenen Index für Liste implementieren?

class mylist(list):
  def index_withoutexception(self,i):
    try:
        return self.index(i)
    except:
        return -1

Sie können also list verwenden und mit Ihrem index2 im Fehlerfall das zurückgeben, was Sie möchten.

Sie können es so verwenden:

  l = mylist([1,2,3,4,5]) # This is the only difference with a real list
  l.append(4) # l is a list.
  l.index_withoutexception(19) # return -1 or what you want
AH
quelle
Beachten Sie, dass dies einen Code beschädigen kann: type(l) == listist Falsehier.
Bfontaine
1
Auch - ich bin nicht positiv, aber es scheint mir, dass wenn das Ziel darin besteht, eine Ausnahme zu vermeiden (was teuer ist, wenn es häufig vorkommt), dies nicht erreicht wird. Es wird -1 zurückgegeben, aber intern wird immer noch eine Ausnahme ausgelöst, die immer noch kostspielig ist.
LogicOnAbstractions
6

TL; DR: Ausnahmen sind Ihr Freund und der beste Ansatz für die Frage, wie angegeben.
Es ist einfacher, um Vergebung zu bitten als um Erlaubnis (EAFP)

Das OP stellte in einem Kommentar klar, dass es für ihren Anwendungsfall eigentlich nicht wichtig war, den Index zu kennen. Wie die akzeptierte Antwort vermerkt, x in somelistist die Verwendung die beste Antwort, wenn Sie sich nicht darum kümmern.

Aber ich gehe davon aus, dass es Ihnen wichtig ist , was der Index ist , wie die ursprüngliche Frage nahelegt . In diesem Fall muss ich feststellen, dass bei allen anderen Lösungen die Liste zweimal gescannt werden muss, was zu einer erheblichen Leistungsminderung führen kann.

Darüber hinaus schrieb der ehrwürdige Raymond Hettinger in einem Kommentar

Selbst wenn wir list.find hätten, das -1 zurückgibt, müssten Sie immer noch testen, ob i == -1 ist, und etwas unternehmen.

Ich werde also auf die Annahme in der ursprünglichen Frage zurückgreifen, dass Ausnahmen vermieden werden sollten. Ich schlage vor, dass Ausnahmen dein Freund sind. Sie sind nichts, vor dem man Angst haben muss, sie sind nicht ineffizient, und tatsächlich müssen Sie mit ihnen vertraut sein, um guten Code zu schreiben.

Daher denke ich, dass die beste Antwort darin besteht, einfach einen Try-außer-Ansatz zu verwenden:

try:
    i = somelist.index(x) 
except ValueError:
    # deal with it

"damit umgehen " bedeutet nur, das zu tun, was Sie tun müssen: i auf einen Sentinel-Wert setzen, eine eigene Ausnahme auslösen, einem anderen Code-Zweig folgen usw.

Dies ist ein Beispiel dafür, warum das Python-Prinzip Leichter um Vergebung als um Erlaubnis zu bitten (EAFP) sinnvoll ist, im Gegensatz zum Wenn-Dann-Sonst-Stil von Look before you leap (LBYL).

nealmcb
quelle
1
So wahr! Ich dachte, ich hätte dieses Problem und dachte zuerst, eine der anderen Lösungen sei gut. Dann schaute ich noch einmal auf meinen Code und stellte fest, dass die Verwendung eines Versuchs ... außer schneller und natürlicher wäre, da ich mich natürlich noch damit befassen muss ...
nealmcb
1
Ich lache laut. Manchmal halten Einsichten nicht an. Ich habe gerade den obigen Kommentar abgegeben, ohne zu bemerken, dass ich die Antwort vor 2 Jahren überhaupt geschrieben hatte. Erst als ich versuchte, meine eigene Antwort abzustimmen, hat mich SO darauf
hingewiesen
Das ist absolut lustig!
T_M
4

Schreiben Sie eine Funktion, die das tut, was Sie brauchen:

def find_in_iterable(x, iterable):
    for i, item in enumerate(iterable):
        if item == x:
            return i
    return None

Wenn Sie nur wissen müssen, ob das Element vorhanden ist, nicht aber den Index, können Sie Folgendes verwenden in:

x in yourlist
Mark Byers
quelle
Danke - aber ich hatte auf etwas Vorverpacktes gehofft
Yarin
4
PS '-1' ist ein gültiger Listenindex - Sie müssen 'None' zurückgeben
Yarin
@Yarin: Der Grund, warum ich -1 gewählt habe, war, dass ich zum Beispiel mit vorhandenen Python-Redewendungen übereinstimmte 'abc'.find('x') == -1, aber Noneauch funktionieren würde. Ich werde meine Antwort aktualisieren.
Mark Byers
1
Ja, das ist seltsam, dass .find () das tut - scheint nicht mit den negativen Indizes von Python übereinzustimmen.
Yarin
3

Ja da ist. Sie können z. mache etwas ähnliches:

test = lambda l, e: l.index(e) if e in l else None

was so funktioniert:

>>> a = ['a', 'b', 'c', 'g', 'c']
>>> test(a, 'b')
1
>>> test(a, 'c')
2
>>> test(a, 't')
None

Im Grunde test() wird also der Index des Elements (zweiter Parameter) innerhalb der angegebenen Liste (erster Parameter) zurückgegeben, sofern er nicht gefunden wurde (in diesem Fall wird er zurückgegeben None, aber es kann alles sein, was Sie für geeignet halten).

Tadeck
quelle
1

Wenn es Ihnen egal ist, wo es sich in der Sequenz befindet, nur seine Anwesenheit, verwenden Sie den inOperator. Andernfalls schreiben Sie eine Funktion, die die Ausnahmebehandlung umgestaltet.

def inlist(needle, haystack):
  try:
    return haystack.index(needle)
  except ...:
    return -1
Ignacio Vazquez-Abrams
quelle
Ich habe eine Antwort veröffentlicht, die die Existenz mithilfe indes Index überprüft und schließlich zurückgibt, aber ich sehe, dass Sie diese Methode kennen und beschlossen haben, Ausnahmen zu behandeln, die möglicherweise ausgelöst werden. Meine Frage ist: Warum haben Sie sich für eine Ausnahme entschieden, anstatt zuerst die haystackExistenz zu überprüfen needle? Gibt es dafür einen Grund?
Tadeck
@Tadeck: Aufgrund der ungeschriebenen Python-Regel "Es ist einfacher, um Vergebung als um Erlaubnis zu bitten".
Ignacio Vazquez-Abrams
1
Danke :) Ich habe es gerade im Python-Glossar gefunden, wo EAFP (leichter um Vergebung als um Erlaubnis zu bitten) als etwas Gegenteiliges zu LBYL (Look Before You Leap) angezeigt wird . Und tatsächlich wurde EAFP als allgemeiner Python-Codierungsstil bezeichnet , so dass es nicht so ungeschrieben ist :) Nochmals vielen Dank!
Tadeck
Du brauchst das nicht wirklich ...in der except ...:Leitung.
swdev
1

hoffe das hilft

lst= ','.join('qwerty').split(',') # create list
i='a'  #srch string
lst.index(i) if i in lst else None
schwarzer Wind
quelle
0

Es gibt keine integrierte Möglichkeit, das zu tun, was Sie tun möchten.

Hier ist ein guter Beitrag, der Ihnen helfen kann: Warum hat die Liste keine sichere "get" -Methode wie das Wörterbuch?

juliomalegria
quelle
In diesem Beitrag geht es um die Array-Indizierung mit dem IndexError: list index out of rangeProblem, nicht um die hier beschriebene index()Methode mit dem ValueError: <value> is not in listProblem.
Nealmcb
0

Ich verwende gerne die List- Klasse von Web2py , die sich im Speichermodul des Gluon-Pakets befindet. Das Speichermodul bietet listenartige (List) und wörterbuchartige (Storage) Datenstrukturen, die keine Fehler auslösen, wenn ein Element nicht gefunden wird.

Laden Sie zuerst die Quelle von web2py herunter und kopieren Sie dann den Gluon-Paketordner in die Site-Pakete Ihrer Python-Installation.

Probieren Sie es jetzt aus:

>>> from gluon.storage import List
>>> L = List(['a','b','c'])
>>> print L(2)
c
>>> print L(3) #No IndexError!
None

Beachten Sie, dass es sich auch wie eine normale Liste verhalten kann:

>>> print L[3]

Traceback (most recent call last):
File "<pyshell#4>", line 1, in <module>
l[3]
IndexError: list index out of range
Himel Das
quelle
gute Idee, danke.)def __call__(self, idx, df=None): return self[idx] if 0<=idx<len(self) else df
Winand