So erhalten Sie das n-te Element einer Python-Liste oder einen Standard, falls nicht verfügbar


143

Ich suche nach einem Äquivalent in Python dictionary.get(key, default)für Listen. Gibt es eine Liner-Sprache, um das n-te Element einer Liste oder einen Standardwert abzurufen, falls dieser nicht verfügbar ist?

Zum Beispiel, wenn ich eine Liste myList erhalten möchte myList[0], oder 5, wenn myListes sich um eine leere Liste handelt.

Vielen Dank.

Antworten:


123
l[index] if index < len(l) else default

Zur Unterstützung negativer Indizes können wir verwenden:

l[index] if -len(l) <= index < len(l) else default

3
Funktioniert nicht, wenn Ihre Liste keinen Namen hat - zum Beispiel in einem Listenverständnis.
Xiong Chiamiov

9
Sie scheinen den Fall des negativen Index vergessen zu haben. Z.B. index == -1000000sollte zurückkehren default.
Nodakai

3
@odakai, guter Punkt. Ich bin manchmal davon gebissen worden. x[index] if 0 <= index < len(x) else defaultwäre besser wenn indexjemals negativ sein kann.
Ben Hoyt

3
@nodakai wow - das ist ein großartiges Beispiel dafür, warum es möglicherweise besser ist, try / Except zu verwenden, als zu versuchen, den Test korrekt zu codieren, damit er niemals fehlschlägt. Ich mag es immer noch nicht, mich auf try / zu verlassen, außer für einen Fall, von dem ich weiß, dass er eintreten wird, aber dies erhöht meine Bereitschaft, darüber nachzudenken.
ToolmakerSteve

6
@ToolmakerSteve: Ihre Formel für valid_index()ist falsch. Negative Indizes sind in Python legal - das sollte auch so sein -len(l) <= index < len(l).
Tim Pietzcker

57
try:
   a = b[n]
except IndexError:
   a = default

Bearbeiten: Ich habe die Prüfung für TypeError entfernt - wahrscheinlich besser, damit der Anrufer damit umgehen kann.


3
Ich mag das. Wickeln Sie es einfach um eine Funktion, damit Sie sie mit einem iterablen Argument aufrufen können. Einfacher zu lesen.
Noufal Ibrahim

35
(a[n:]+[default])[0]

Dies ist wahrscheinlich besser, wenn es agrößer wird

(a[n:n+1]+[default])[0]

Dies funktioniert, weil if a[n:]eine leere Liste ist, wennn => len(a)

Hier ist ein Beispiel, wie dies funktioniert range(5)

>>> range(5)[3:4]
[3]
>>> range(5)[4:5]
[4]
>>> range(5)[5:6]
[]
>>> range(5)[6:7]
[]

Und der volle Ausdruck

>>> (range(5)[3:4]+[999])[0]
3
>>> (range(5)[4:5]+[999])[0]
4
>>> (range(5)[5:6]+[999])[0]
999
>>> (range(5)[6:7]+[999])[0]
999

5
Würden Sie dies in tatsächlichen Code ohne einen Kommentar schreiben, um es zu erklären?
Peter Hansen

1
@ Peter Hansen, nur wenn ich Golf gespielt habe;) Es funktioniert jedoch auf allen Versionen von Python. Die akzeptierte Antwort funktioniert nur auf 2.5+
John La Rooy

3
Es ist jedoch erforderlich, 3 temporäre Listen zu erstellen und auf 2 Indizes zuzugreifen, um ein Element auszuwählen.
Joachim Jablon

Während ich dies niemals in "echtem" Code tun würde, ist es ein netter, prägnanter Einzeiler, den ich problemlos in einer Python-REPL verwenden kann, sodass Sie meine positive Bewertung erhalten.
Cookyt

next(iter(lst[i:i+1]), default)- nur ein weiterer Eintrag im kryptisch hässlichen Einzeiler-Wettbewerb.
JFS

28

Habe gerade das entdeckt:

next(iter(myList), 5)

iter(l)Gibt einen Iterator zurück myList, next()verbraucht das erste Element des Iterators und löst einen StopIterationFehler aus, außer wenn er mit einem Standardwert aufgerufen wird, was hier der Fall ist, das zweite Argument.5

Dies funktioniert nur, wenn Sie das 1. Element möchten, was in Ihrem Beispiel der Fall ist, aber nicht im Text Ihrer Frage, also ...

Außerdem müssen keine temporären Listen im Speicher erstellt werden, und es funktioniert für jede Art von iterierbaren Listen, auch wenn es keinen Namen hat (siehe Xiong Chiamiovs Kommentar zu gruszczys Antwort).


3
Kombiniert mit den anderen Antworten: next(iter(myList[n:n+1]), 5) Jetzt funktioniert es für das nth-Element.
Alfe

Das würde mit Nicht-Listen nicht funktionieren. Versuchen Sie an dieser Stelle: Mit Ausnahme eines IndexError liest sich IMHO wie eine bessere Idee. Außerdem wird eine Liste im Speicher erstellt.
Joachim Jablon

Die tryVariante ist kein Einzeiler (fragen Sie nach OP). Es funktioniert nur für Listen, da myListes sich um eine von OP angegebene Liste handelt (um genau zu sein, es ist etwas Indizierbares). Das Erstellen einer Kopie im Speicher ist hier nicht teuer, da ich hier eine Liste mit einem einzelnen (oder keinem) Element erstelle. Sicher, ein wenig Aufwand, aber nicht erwähnenswert, es sei denn, Sie tun dies millionenfach in einer Schleife. Übrigens denke ich, dass das Erstellen und Abfangen einer IndexErrorAusnahme wahrscheinlich teurer ist.
Alfe

Lesbarkeit zählt :) Wenn Sie an dem Punkt angelangt sind, an dem das Auslösen eines IndexError erhebliche Kosten verursacht, sollten Sie das Ganze möglicherweise in Python ausführen.
Joachim Jablon

20
(L[n:n+1] or [somedefault])[0]

1
+1, weil ich dadurch lernen musste, was ich getan [] or ...habe. Ich persönlich würde jedoch nur die akzeptierte Lösung verwenden, da sie leicht zu lesen ist (für Anfänger). Zugegeben, wenn man es mit einem 'def' in einen Kommentar einwickelt, ist das größtenteils kein Problem.
ToolmakerSteve

Was ist, wenn L[n] == Falseoder L[n] == Noneoder L[n] == []global etwas, das als falsch bewertet wird?
Joachim Jablon

@ JoachimJablon: Funktioniert immer noch. Das Slice gibt eine Liste zurück und[False] ist wahr.
Ignacio Vazquez-Abrams

Oh, ich habe nicht bemerkt, dass die Liste überprüft wurde und nicht der Wert.
Joachim Jablon

Warum wickelst du das in ein Tupel? Meiner Ansicht nachmyval = l[n:n+1] or [somedefault] würde gut funktionieren?
Rotareti

8

... auf der Suche nach einem Äquivalent in Python dict.get(key, default)für Listen

Es gibt ein itertools-Rezept , das dies für allgemeine iterables tut. Der Einfachheit halber können Sie> pip install more_itertools diese Drittanbieter-Bibliothek importieren, die solche Rezepte für Sie implementiert:

Code

import more_itertools as mit


mit.nth([1, 2, 3], 0)
# 1    

mit.nth([], 0, 5)
# 5    

Detail

Hier ist die Umsetzung des nthRezepts:

def nth(iterable, n, default=None):
    "Returns the nth item or a default value"
    return next(itertools.islice(iterable, n, None), default)

Mögen dict.get() , gibt dieses Tool eine Standard für fehlende Indizes. Es gilt für allgemeine iterables:

mit.nth((0, 1, 2), 1)                                      # tuple
# 1

mit.nth(range(3), 1)                                       # range generator (py3)
# 1

mit.nth(iter([0, 1, 2]), 1)                                # list iterator 
# 1  

2

Eine billige Lösung ist es, wirklich ein Diktat mit Aufzählung zu machen und .get()wie gewohnt zu verwenden, wie

 dict(enumerate(l)).get(7, my_default)

1

Wenn Sie @ Joachim's mit dem oben genannten kombinieren, können Sie es verwenden

next(iter(my_list[index:]), default)

Beispiele:

next(iter(range(10)[8:]), 11)
8
>>> next(iter(range(10)[12:]), 11)
11

Oder vielleicht klarer, aber ohne die len

my_list[index] if my_list[index:] else default

1

Verwenden Sie Python 3.4 contextlib.suppress(exceptions), um eine getitem()ähnliche Methode wie zu erstellen getattr().

import contextlib

def getitem(iterable, index, default=None):
    """Return iterable[index] or default if IndexError is raised."""
    with contextlib.suppress(IndexError):
        return iterable[index]
    return default
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.