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.

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)

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).


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]

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

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")


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 ).


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)

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.


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

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


-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)

1
Chodziło o to, aby „ znaleźć pierwszy indeks na liście, który jest większy niż x ”.
— Gino Mempin
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.