Pierwszy indeks listy Pythona większy niż x?

81

Jaki byłby najbardziej Pythonowy sposób na znalezienie pierwszego indeksu na liście, który jest większy niż x?

Na przykład z

list = [0.5, 0.3, 0.9, 0.8]

Funkcja

f(list, 0.7)

wróci

2.
c00kiemonster
źródło
57
nie używaj „list” jako nazwy zmiennej ...
mshsayem
11
Masz na myśli „pytoniczny”. Według urbandictionary.com/define.php?term=Pythonesque , „pythonesque” oznacza „surrealistyczny, absurdalny” i nie sądzę, że tego właśnie szukasz: P
Roberto Bonvallet
1
Pytanie jest niejednoznaczne. Czy odpowiedź brzmi „ 2ponieważ” 0.9 > 0.7czy „ponieważ” 0.8 > 0.7? Innymi słowy, czy wyszukujesz sekwencyjnie, czy w kolejności rosnących wartości?
Sergey Orshanskiy
Głosowałem za zamknięciem tego pytania jako duplikatu, zamiast robić odwrotnie, ponieważ nowsze pytanie jest bardziej ogólne.
Cristian Ciupitu

Odpowiedzi:

118
next(x[0] for x in enumerate(L) if x[1] > 0.7)
Ignacio Vazquez-Abrams
źródło
29
+1: Chociaż wolałbym uniknąć magicznych liczb: dalej (idx dla idx, wartość w enumerate (L), jeśli wartość> 0,7)
truppo
38
+1 za prostotę i next(), ale może to za czytelność:next(i for i,v in enumerate(L) if v > 0.7)
Will Hardy
14
Chociaż wygląda to ładnie, przypadek, w którym nie ma wyniku, spowoduje mylące zatrzymanie.
Virgil Dupras
3
@Wim: Ale potem cofasz się do oceny całej sekwencji. Użyj itertools.chain()zamiast dodawać takie listy.
Ignacio Vazquez-Abrams,
3
@Wim, nie potrzebujesz łańcucha () tutaj. next () przyjmuje drugi argument:next((i for i, x in enumerate(L) if x > value), -1)
jfs
35

jeśli lista jest posortowana, bisect.bisect_left(alist, value)jest szybsza w przypadku dużej listy niż next(i for i, x in enumerate(alist) if x >= value).

jfs
źródło
Dobra odpowiedź - na pewno było to dla mnie od 5 do 6 razy szybciej, używając małej, posortowanej listy 4-elementowej, ale (nie jestem pewien, czy popełniam błąd), ale kiedy używam timeit z długą listą 10000 elementów tablicy numpy Uważam jednak, że jest mniej więcej dwa razy wolniejszy niż powyższa odpowiedź ze zrozumieniem listy, co mnie zaskoczyło.
Adrian Tompkins
1
@AdrianTompkins: coś jest nie tak z twoim benchmarkiem. bisect_leftjest O (log n), podczas gdy listcomp jest O (n), tj. im większy n, tym większa przewaga po bisect_left()stronie. Próbowałem znaleźć indeks 500_000w range(10**6)użyciu bisect_left()-> 3,75 mikrosekund i używając genexpr z next()-> 51,0 milisekund [ 10_000razy] wolniej, jak oczekiwano.
jfs
16
filter(lambda x: x>.7, seq)[0]
Lecieć jak po sznurku
źródło
4
-1: Chociaż technicznie poprawne, nie używaj filtru, w którym rozumienie listy jest zarówno bardziej czytelne, jak i
wydajniejsze
filter (lambda x: x [1]> .7, enumerate (seq)) [0] [0] - proste wyszukiwanie liniowe
lowtech
4
Filtr @truppo w pythonie 3 zwraca generator, więc nie powinien być gorszy niż zrozumienie listy? Również ten sposób wydaje mi się bardziej czytelny niż rozwiązanie wyliczeniowe.
BubuIIC
Jedną rzeczą, która nie jest przyjemna w tym przypadku, jest to, że przechodzisz do obsługi wyjątków, jeśli w sekwencji nie ma elementu większego niż .7.
Brian C.
Rozwiązanie jest technicznie nieprawidłowe. Autor pytania zapytał, jak znaleźć indeks elementu na liście. Ale to rozwiązanie zamiast tego zwraca rekord. Eventmore w Pythonie 3.8 jest wolniejsze niż bisect_left()(najszybsze) i 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
ghostdog74
źródło
2
nie powiedzie się, jeśli „x” jest większe niż jakakolwiek inna wartość na liście
mshsayem
2
@mshsayem: Problem jest źle zdefiniowany w tym przypadku. Porażka może być słuszna.
S.Lott,
@ S.Loot: Słuszna uwaga. W przeciwnym wypadku, jeśli nie w wynikach lista w zrozumiały błąd podczas przypisywania to do zmiennej: IndexError: list index out of range. Korzystanie index = next[ n for n,i in enumerate(alist) if i>0.7 ]błąd otrzymujemy: NameError: name 'index' is not defined. nextjest nieco szybszy: różnica czasu wynosi 12,7 ns w porównaniu z 11,9 ns dla 60 000 liczb.
Leo
11
for index, elem in enumerate(elements):
    if elem > reference:
        return index
raise ValueError("Nothing Found")
Virgil Dupras
źródło
4

Inny:

map(lambda x: x>.7, seq).index(True)
Lecieć jak po sznurku
źródło
3

1) NUMPY ARGWHERE, ogólne listy

Jeśli z przyjemnością używasz numpy, na ogólnych listach (posortowanych lub nieposortowanych) będą działać następujące czynności:

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

lub jeśli potrzebujesz odpowiedzi w postaci listy:

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

lub jeśli potrzebujesz odpowiedzi w postaci liczby całkowitej:

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

2) NUMPY SEARCHSORTED, posortowane listy (bardzo wydajne przy wyszukiwaniu list)

Jeśli jednak twoja lista wyszukiwania jest posortowana, znacznie czystsze i przyjemniejsze jest użycie funkcji np.searchsorted :

numpy.searchsorted(searchlist,x)

Zaletą korzystania z tej funkcji jest to, że oprócz wyszukiwania pojedynczej wartości x, x może być również listą, tj. Można również zwrócić listę indeksów dla listy wyszukiwanych wartości [x1, x2, x3 .. xn ], ( i jest to bardzo wydajne w porównaniu ze zrozumieniem listy w tym przypadku ).

Adrian Tompkins
źródło
2

Miałem podobny problem, gdy moja lista była bardzo długa. rozwiązania oparte na zrozumieniu lub filtrowaniu przeszłyby przez całą listę. itertools.takewhile przerwie pętlę, gdy warunek stanie się fałszywy za pierwszym razem:

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)
lowtech
źródło
1
dlaczego po prostu nie piszesz def f (l, b): return len (list (takewhile (lambda x: x [1] <= b, enumerate (l))))?
Avo Asatryan
2

Wiem, że jest już wiele odpowiedzi, ale czasami mam wrażenie, że słowo pythonic jest tłumaczone na „jednolinijkowy”.

Kiedy myślę, że lepsza definicja jest bliższa tej odpowiedzi :

„Wykorzystywanie funkcji języka Python do tworzenia kodu, który jest jasny, zwięzły i łatwy w utrzymaniu”.

Chociaż niektóre z powyższych odpowiedzi są zwięzłe, nie uważam ich za jasne i zrozumienie ich zajmie trochę czasu początkującym programistom, dlatego nie są one niezwykle łatwe w utrzymaniu dla zespołu zbudowanego na wielu poziomach umiejętności.

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)

lub

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)

Myślę, że powyższe jest łatwo zrozumiałe dla początkujących i nadal jest wystarczająco zwięzłe, aby zaakceptować je każdy doświadczony programista Pythona.

Myślę, że pisanie głupiego kodu jest pozytywne.

Jeff Tilton
źródło
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
Lecieć jak po sznurku
źródło
Wygląda całkiem nieźle. Ale teoretycznie przejdzie przez całą listę, a następnie zwróci pierwszy wynik (większy niż x), prawda? Czy jest jakiś sposób, aby zatrzymać się zaraz po znalezieniu pierwszego wyniku?
c00kiemonster
co jest złego w przechodzeniu przez całą listę? jeśli pierwsza wartość większa niż 0,7 znajduje się blisko końca listy, nie ma to znaczenia.
ghostdog74
3
Prawdziwe. Ale w tym konkretnym przypadku listy, na których zamierzam używać funkcji, są dość długie, więc wolałbym, aby przerwał przeglądanie, gdy tylko zostanie znalezione dopasowanie ...
c00kiemonster
bez względu na to, czy jest długa, czy nie, jeśli pierwsza wartość jest ostatnią drugą pozycją na liście, nadal będziesz musiał przejść całą listę, aby się tam dostać!
ghostdog74
4
@ ghostdog74: Tak, ale nie jest to powód, aby wszystkie przypadki były najgorszymi.
UncleBens
0

Możesz to również zrobić za pomocą numpy:

import numpy as np

list(np.array(SearchList) > x).index(True)
Prabhakaran Thirugnanam
źródło
-1

Spróbuj tego:

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

przykładowy kod:

Renumerate(range(10))

wynik:

(10, 0)
(9, 1)
(8, 2)
(7, 3)
(6, 4)
(5, 5)
(4, 6)
(3, 7)
(2, 8)
(1, 9)
Navid
źródło
1
Chodziło o to, aby „ znaleźć pierwszy indeks na liście, który jest większy niż x ”.
Gino Mempin