Chcę idiomatycznego sposobu na znalezienie pierwszego elementu na liście, który pasuje do predykatu.
Obecny kod jest dość brzydki:
[x for x in seq if predicate(x)][0]
Myślałem o zmianie tego na:
from itertools import dropwhile
dropwhile(lambda x: not predicate(x), seq).next()
Ale musi być coś bardziej eleganckiego ... I byłoby miło, gdyby zwracało None
wartość, zamiast zgłaszać wyjątek, jeśli nie zostanie znalezione dopasowanie.
Wiem, że mógłbym po prostu zdefiniować funkcję taką jak:
def get_first(predicate, seq):
for i in seq:
if predicate(i): return i
return None
Ale rozpoczęcie wypełniania kodu takimi funkcjami użytkowymi jest zupełnie bez smaku (a ludzie prawdopodobnie nie zauważą, że już tam są, więc mają tendencję do powtarzania się w czasie), jeśli istnieją wbudowane narzędzia, które już zapewniają to samo.
Odpowiedzi:
Aby znaleźć pierwszy element w sekwencji,
seq
który pasuje do apredicate
:Lub (
itertools.ifilter
w Pythonie 2) :Podnosi się,
StopIteration
jeśli nie ma.Aby wrócić,
None
jeśli nie ma takiego elementu:Lub:
źródło
next
który jest używany zamiast zgłaszania wyjątku.next()
jest dostępny od wersji Pythona 2.6. Możesz przeczytać stronę Co nowego, aby szybko zapoznać się z nowymi funkcjami.seq.find(&method(:predicate))
lub jeszcze bardziej zwięzłe, na przykład metody:[1,1,4].find(&:even?)
ifilter
została zmieniona nafilter
w Pythonie 3.Możesz użyć wyrażenia generatora z wartością domyślną, a następnie
next
:Chociaż w przypadku tego jednowierszowego kodu musisz używać Pythona> = 2.6.
Ten dość popularny artykuł dalej omawia ten problem: Najczystsza funkcja znajdowania na liście w Pythonie? .
źródło
Nie sądzę, żeby było coś złego w obu rozwiązaniach, które zaproponowałeś w swoim pytaniu.
We własnym kodzie zaimplementowałbym to jednak w następujący sposób:
Składnia with
()
tworzy generator, który jest bardziej wydajny niż generowanie całej listy naraz[]
.źródło
[]
możesz napotkać problemy, jeśli iterator nigdy się nie skończy lub jego elementy są trudne do utworzenia, im później to ...'generator' object has no attribute 'next'
na Pythonie 3.Odpowiedź JF Sebastiana jest najbardziej elegancka, ale wymaga Pythona 2.6, jak wskazał Fortran.
Dla wersji Pythona <2.6, oto najlepsze, co mogę wymyślić:
Alternatywnie, jeśli potrzebowałeś listy później (lista obsługuje StopIteration) lub potrzebujesz czegoś więcej niż tylko pierwszego, ale nadal nie wszystkiego, możesz to zrobić za pomocą islice:
AKTUALIZACJA: Chociaż osobiście używam predefiniowanej funkcji o nazwie first (), która przechwytuje StopIteration i zwraca None, Oto możliwe ulepszenie w stosunku do powyższego przykładu: unikaj używania filtra / ifilter:
źródło