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.

user265454
quelle

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
gruszczy
quelle
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.

Tim Pietzcker
quelle
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
John La Rooy
quelle
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).

Joachim Jablon
quelle
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]
Ignacio Vazquez-Abrams
quelle
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  
Pylang
quelle
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)
Scorchio
quelle
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
serv-inc
quelle
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
Harvey
quelle