Erster Python-Listenindex größer als x?


81

Was wäre der pythonischste Weg, um den ersten Index in einer Liste zu finden, der größer als x ist?

Zum Beispiel mit

list = [0.5, 0.3, 0.9, 0.8]

Die Funktion

f(list, 0.7)

würden zurückkehren

2.

56
Verwenden Sie 'Liste' nicht als Variablennamen ...
mshsayem

11
Du meinst "pythonisch". Laut urbandictionary.com/define.php?term=Pythonesque bedeutet "pythonesque" "surreal, absurd", und ich glaube nicht, dass Sie danach suchen: P
Roberto Bonvallet

1
Die Frage ist nicht eindeutig. Ist die Antwort 2weil 0.9 > 0.7oder weil 0.8 > 0.7? Mit anderen Worten, suchen Sie nacheinander oder in der Reihenfolge steigender Werte?
Sergey Orshanskiy


Ich habe dafür gestimmt, diese Frage als Duplikat zu schließen, anstatt umgekehrt, weil die neuere Frage allgemeiner ist.
Cristian Ciupitu

Antworten:


116
next(x[0] for x in enumerate(L) if x[1] > 0.7)

29
+1: Obwohl ich es vorziehen würde, die magischen Zahlen zu vermeiden: next (idx für idx, Wert in Aufzählung (L), wenn Wert> 0,7)
Truppo

37
+1 für die Einfachheit und next(), aber vielleicht für die Lesbarkeit:next(i for i,v in enumerate(L) if v > 0.7)
Will Hardy

13
Dies sieht zwar gut aus, aber der Fall, in dem kein Ergebnis vorliegt, führt zu einer verwirrenden StopIteration.
Virgil Dupras

2
@flybywire: next()ist in 2.6+. Nennen Sie die next()Methode des Genex in früheren Versionen.
Ignacio Vazquez-Abrams

3
@Wim: Aber dann kehren Sie zur Auswertung der gesamten Sequenz zurück. Verwenden Sie itertools.chain()diese Option, anstatt solche Listen hinzuzufügen.
Ignacio Vazquez-Abrams

35

Wenn die Liste sortiert ist, bisect.bisect_left(alist, value)ist sie für eine große Liste schneller als next(i for i, x in enumerate(alist) if x >= value).


Schöne Antwort - Es war definitiv 5 bis 6 Mal schneller für mich, eine kleine sortierte Liste mit 4 Elementen zu verwenden, aber (nicht sicher, ob ich einen Fehler mache), aber wenn ich dies mit timeit mit einer langen Liste von 10000 Element-Numpy-Arrays zeitlich festlege Ich finde es ungefähr doppelt so langsam wie die Antwort auf das Listenverständnis oben, worüber ich überrascht war.
Adrian Tompkins

1
@AdrianTompkins: Mit Ihrem Benchmark stimmt etwas nicht. bisect_leftist O (log n), während listcomp O (n) ist, dh je größer der n, desto mehr Vorteil auf der bisect_left()Seite. Ich habe versucht , finden Index 500_000in range(10**6)Verwendung bisect_left()-> 3,75 Mikrosekunden und mit Hilfe des genexpr mit next()-> 51,0 Millisekunden [ 10_000mal] langsamer als erwartet.
JFS

16
filter(lambda x: x>.7, seq)[0]

4
-1: Obwohl technisch korrekt, verwenden Sie keinen Filter, bei dem ein Listenverständnis sowohl lesbarer als auch leistungsfähiger ist
Truppo

Filter (Lambda x: x [1]> .7, Aufzählung (seq)) [0] [0] - einfache lineare Suche
Lowtech

4
@truppo Filter in Python 3 gibt einen Generator zurück, also sollte es nicht schlechter sein als ein Listenverständnis? Auch finde ich diesen Weg besser lesbar als die Aufzählungslösung.
BubuIIC

Eine Sache, die an diesem nicht gut ist, ist, dass Sie in die Ausnahmebehandlung geraten, wenn kein Element in der Sequenz größer als .7 ist.
Brian C.

Die Lösung ist technisch falsch. Der Frageautor fragte, wie der Index des Elements in der Liste gefunden werden kann. Diese Lösung gibt jedoch stattdessen einen Datensatz zurück. Eventmore in Python 3.8 ist es langsamer als bisect_left()(am schnellsten) und enumerate().
Sergey Nevmerzhitsky

16
>>> alist= [0.5, 0.3, 0.9, 0.8]
>>> [ n for n,i in enumerate(alist) if i>0.7 ][0]
2

2
es wird fehlschlagen, wenn 'x' größer als jeder andere Wert in der Liste ist
mshsayem

2
@mshsayem: Das Problem ist für diesen Fall schlecht definiert. Ein Misserfolg kann das Richtige sein.
S.Lott

@ S.Loot: Guter Punkt. Wenn dies nicht in der Liste enthalten ist, führt dies zu einem verständlichen Fehler, wenn dies einer Variablen zugewiesen wird : IndexError: list index out of range. Die Verwendung von index = next[ n for n,i in enumerate(alist) if i>0.7 ]Fehler ergibt : NameError: name 'index' is not defined. nextist etwas schneller: Der Zeitunterschied beträgt 12,7 ns gegenüber 11,9 ns für 60 000 Nummern.
Leo

10
for index, elem in enumerate(elements):
    if elem > reference:
        return index
raise ValueError("Nothing Found")


2

Ich hatte ein ähnliches Problem, als meine Liste sehr lang war. Verständnis oder filterbasierte Lösungen würden die ganze Liste durchlaufen. itertools.takewhile unterbricht die Schleife, sobald die Bedingung beim ersten Mal falsch wird:

from itertools import takewhile

def f(l, b): return len([x for x in takewhile(lambda x: x[1] <= b, enumerate(l))])

l = [0.5, 0.3, 0.9, 0.8]
f(l, 0.7)

warum schreibst du nicht def f (l, b): return len (list (takewhile (lambda x: x [1] <= b, enumerate (l))))?
Avo Asatryan

2

Ich weiß, dass es bereits viele Antworten gibt, aber manchmal habe ich das Gefühl, dass das Wort Python in "Einzeiler" übersetzt wird.

Wenn ich denke, dass eine bessere Definition dieser Antwort näher kommt :

"Nutzen Sie die Funktionen der Python-Sprache, um Code zu erstellen, der klar, präzise und wartbar ist."

Obwohl einige der oben genannten Antworten prägnant sind, finde ich sie nicht klar und es würde eine Weile dauern, bis ein Programmieranfänger sie versteht, sodass sie für ein Team mit vielen Fähigkeiten nicht besonders wartbar sind.

l = [0.5, 0.3, 0.9, 0.8]

def f(l, x):
    for i in l:
        if i >x: break
    return l.index(i)


f(l,.7)

oder

l = [0.5, 0.3, 0.9, 0.8]

def f(l, x):
    for i in l:
        if i >x: return l.index(i)



f(l,.7)

Ich denke, dass das Obige für einen Neuling leicht verständlich ist und immer noch prägnant genug ist, um von jedem erfahrenen Python-Programmierer akzeptiert zu werden.

Ich denke, das Schreiben von dummem Code ist positiv.


2

1) NUMPY SOLUTION, allgemeine Listen

Wenn Sie gerne numpy verwenden, funktioniert Folgendes für allgemeine Listen (sortiert oder unsortiert):

numpy.argwhere(np.array(searchlist)>x)[0]

oder wenn Sie die Antwort als Liste benötigen:

numpy.argwhere(np.array(searchlist)>x).tolist()[0]

oder wenn Sie die Antwort als ganzzahligen Index benötigen:

numpy.argwhere(np.array(searchlist)>x).tolist()[0][0]

2) NUMPY SOLUTION, sortierte Listen

Wenn Ihre Suchliste jedoch sortiert ist, ist es viel sauberer und schöner, die Funktion np.searchsorted zu verwenden :

numpy.searchsorted(searchlist,x)

Das Schöne an dieser Funktion ist, dass Sie neben der Suche nach einem einzelnen Wert x auch eine Liste von Indizes für eine Liste von Werten x zurückgeben können ( und dies ist in diesem Fall im Vergleich zum Listenverständnis sehr effizient ).


1
>>> f=lambda seq, m: [ii for ii in xrange(0, len(seq)) if seq[ii] > m][0]
>>> f([.5, .3, .9, .8], 0.7)
2

Das sieht ziemlich schick aus. Aber theoretisch wird es die gesamte Liste durchlaufen und dann das erste Ergebnis (größer als x) zurückgeben, oder? Gibt es eine Möglichkeit, eine zu erstellen, die direkt nach dem ersten Ergebnis stoppt?
c00kiemonster

Was ist falsch daran, die ganze Liste zu durchlaufen? Wenn der erste Wert größer als 0,7 am Ende der Liste liegt, macht dies keinen Unterschied.
Ghostdog74

3
Wahr. Aber in diesem speziellen Fall sind die Listen, für die ich die Funktion verwenden möchte, ziemlich lang, daher würde ich es vorziehen, das Durchlaufen zu beenden, sobald eine Übereinstimmung gefunden wird ...
c00kiemonster

ob es lang ist oder nicht, wenn der erste Wert das letzte zweite Element der Liste ist, müssen Sie immer noch die gesamte Liste durchlaufen, um dorthin zu gelangen!
Ghostdog74

4
@ ghostdog74: Ja, aber dies ist kein Grund zu wollen, dass alle Fälle die schlimmsten Fälle sind.
Onkel Bens


-1

Probier diese:

def Renumerate(l):
    return [(len(l) - x, y) for x,y in enumerate(l)]

Beispielcode:

Renumerate(range(10))

Ausgabe:

(10, 0)
(9, 1)
(8, 2)
(7, 3)
(6, 4)
(5, 5)
(4, 6)
(3, 7)
(2, 8)
(1, 9)

1
Die Frage war, " den ersten Index in einer Liste zu finden, die größer als x ist ".
Gino Mempin
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.