2012-03-26 15 views
205

Jaki byłby najbardziej elegancki i skuteczny sposób znajdowania/zwracania pierwszego elementu listy, który pasuje do określonego kryterium?znaleźć pierwszy element sekwencji, który pasuje do kryterium

Na przykład, jeśli mam listę obiektów i chciałbym uzyskać pierwszy obiekt tych z atrybutem obj.val==5. Mógłbym oczywiście użyć rozumienia listowego, ale wymagałoby to O (n), a jeśli n jest duże, to marnotrawstwo. Mogłem także użyć pętli z break, gdy tylko kryterium zostało spełnione, ale pomyślałem, że może być bardziej pytonowo/eleganckie rozwiązanie.

+2

co, jeśli chcemy uzyskać pozycję i indeks? –

+1

@CharlieParker, aby uzyskać zarówno indeks, jak i element, użyj wyliczenia() - next ((idx, obj) dla idx, obj w wyliczeniu (objs), jeśli obj.val == 5) –

Odpowiedz

367

Jeśli nie mają żadnych innych indeksów lub sortowane informacje dla swoich obiektów, a następnie trzeba będzie iteracji, aż zostanie znaleziony taki obiekt:

next(obj for obj in objs if obj.val==5) 

Jest to jednak szybciej niż się pełna lista zrozumieniem. Porównanie tych dwóch:

[i for i in xrange(100000) if i == 1000][0] 

next(i for i in xrange(100000) if i == 1000) 

Pierwszy wymaga 5.75ms, drugi 58.3μs (100 razy szybciej, ponieważ pętla 100 razy krótszy).

+93

'next' również dostarcza' domyślny argument, w przypadku gdy nie istnieje obiekt. Na przykład. 'next ((i dla i w zakresie (500) jeśli i> 600), 600)' zwróci 600. – Darthfett

+22

Python [** 'next()' **] (http://docs.python.org/2 /library/functions.html#next) –

+5

Cóż, to jest to, ale spodziewałem się, że odpowiednia odpowiedź będzie wyglądać na bardziej cool. Zawsze reklamujemy Pythona za to, że jest taki elegancki. Jeśli chcesz, aby była solidna, powinieneś podać 'default' (np.' None') - i nie musisz zapominać, że 'wyrażenie Generator musi być nawiasowane, jeśli nie jedynym argumentem' ... Cóż, jak to wpływa na czytelność ? Na przykład. pierwsze nieprzyjmowanie ścieżkowe: 'next ((arg dla arg w sys.argv jeśli nie os.path.exists (arg)), None)' - niezbyt przyjazny. –

2
a=[100,200,300,400,500] 
def search(b): 
try: 
    k=a.index(b) 
    return a[k] 
except ValueError: 
    return 'not found' 
print(search(500)) 

będzie to powrót obiektu, jeśli stwierdzono inaczej to będzie powrót „nie znaleziono”

+0

To jest miłe, ale działa tylko wtedy, gdy kryterium jest porównanie z pozycją na liście. Szukałem bardziej ogólnego rozwiązania, aby obsłużyć szerszy zakres wyboru – Jonathan

+0

, ale @ Jonaton w swoim pytaniu, o którym wspomniałeś ** Sprawny sposób na znalezienie \ zwrócenie pierwszego elementu listy **, więc powyższa lista a = [100,200,300,400,500] może zawierać dowolny rodzaj obiektu nie tylko liczby. –

+1

i kończę zdanie słowem "... które pasuje do pewnych kryteriów", co nie jest równoznaczne z dopasowaniem do równości lub tożsamości :) Zrobiłem +1, ponieważ uważam, że twoje rozwiązanie jest dobre dla równości \ tożsamość prywatna sprawa – Jonathan

Powiązane problemy