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?
+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.
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 inenumerate(alist) if i>0.7 ][0]
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 inenumerate(elements):
if elem > reference:
return index
raise ValueError("Nothing Found")
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
deff(l, b):returnlen([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)
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]
deff(l, x):for i in l:
if i >x: breakreturn l.index(i)
f(l,.7)
lub
l = [0.5, 0.3, 0.9, 0.8]
deff(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.
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)
2
ponieważ”0.9 > 0.7
czy „ponieważ”0.8 > 0.7
? Innymi słowy, czy wyszukujesz sekwencyjnie, czy w kolejności rosnących wartości?Odpowiedzi:
next(x[0] for x in enumerate(L) if x[1] > 0.7)
źródło
next()
, ale może to za czytelność:next(i for i,v in enumerate(L) if v > 0.7)
itertools.chain()
zamiast dodawać takie listy.next((i for i, x in enumerate(L) if x > value), -1)
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)
.źródło
bisect_left
jest O (log n), podczas gdy listcomp jest O (n), tj. im większyn
, tym większa przewaga pobisect_left()
stronie. Próbowałem znaleźć indeks500_000
wrange(10**6)
użyciubisect_left()
-> 3,75 mikrosekund i używając genexpr znext()
-> 51,0 milisekund [10_000
razy] wolniej, jak oczekiwano.filter(lambda x: x>.7, seq)[0]
źródło
bisect_left()
(najszybsze) ienumerate()
.>>> alist= [0.5, 0.3, 0.9, 0.8] >>> [ n for n,i in enumerate(alist) if i>0.7 ][0] 2
źródło
IndexError: list index out of range
. Korzystanieindex = next[ n for n,i in enumerate(alist) if i>0.7 ]
błąd otrzymujemy:NameError: name 'index' is not defined
.next
jest nieco szybszy: różnica czasu wynosi 12,7 ns w porównaniu z 11,9 ns dla 60 000 liczb.for index, elem in enumerate(elements): if elem > reference: return index raise ValueError("Nothing Found")
źródło
Inny:
map(lambda x: x>.7, seq).index(True)
źródło
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 :
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 ).
źródło
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)
źródło
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.
źródło
>>> 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
źródło
Możesz to również zrobić za pomocą
numpy
:import numpy as np list(np.array(SearchList) > x).index(True)
źródło
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)
źródło