Я хочу идиоматический способ найти первый элемент в списке, который соответствует предикату.
Текущий код довольно уродлив:
[x for x in seq if predicate(x)][0]
Я думал об изменении его на:
from itertools import dropwhile
dropwhile(lambda x: not predicate(x), seq).next()
Но должно быть что-то более элегантное ... И было бы неплохо, если бы оно возвращало None
значение, а не вызывало исключение, если совпадение не найдено.
Я знаю, что мог бы просто определить функцию как:
def get_first(predicate, seq):
for i in seq:
if predicate(i): return i
return None
Но начинать заполнение кода такими служебными функциями довольно безвкусно (и люди, вероятно, не заметят, что они уже есть, поэтому они имеют тенденцию повторяться со временем), если есть встроенные модули, которые уже предоставляют то же самое.
Ответы:
Чтобы найти первый элемент в последовательности,
seq
которая соответствуетpredicate
:Или (
itertools.ifilter
на Python 2) :Он поднимается,
StopIteration
если его нет.Чтобы вернуть,
None
если такого элемента нет:Или:
источник
next
который используется вместо вызова исключения.next()
доступен с Python 2.6. Вы можете прочитать страницу Что нового, чтобы быстро ознакомиться с новыми функциями.seq.find(&method(:predicate))
или даже более краткий для методов экземпляра, например:[1,1,4].find(&:even?)
ifilter
был переименованfilter
в Python 3.Вы можете использовать выражение генератора со значением по умолчанию, а затем
next
оно:Хотя для этой однострочной вы должны использовать Python> = 2.6.
Эта довольно популярная статья дополнительно обсуждает эту проблему: Чистая функция поиска в списке Python? ,
источник
Я не думаю, что что-то не так с любым решением, которое вы предложили в своем вопросе.
В моем собственном коде я бы реализовал это так:
Синтаксис с
()
создает генератор, который более эффективен, чем генерация всего списка одновременно[]
.источник
[]
вами могут возникнуть проблемы, если итератор никогда не заканчивается или его элементы трудно создать, чем позже он становится ...'generator' object has no attribute 'next'
на Python 3.Ответ Дж. Ф. Себастьяна самый элегантный, но, как указал Фортран, требует python 2.6.
Для Python версии <2.6 вот лучшее, что я могу придумать:
В качестве альтернативы, если вам нужен список позже (list обрабатывает StopIteration), или вам нужно больше, чем просто первый, но все же не все, вы можете сделать это с помощью islice:
ОБНОВЛЕНИЕ: Хотя я лично использую предопределенную функцию first (), которая перехватывает StopIteration и возвращает None, вот возможное улучшение по сравнению с приведенным выше примером: избегайте использования filter / ifilter:
источник