Я хотел бы получить первый элемент из списка, соответствующего условию. Важно, чтобы полученный метод не обрабатывал весь список, который может быть довольно большим. Например, следующая функция является адекватной:
def first(the_iterable, condition = lambda x: True):
for i in the_iterable:
if condition(i):
return i
Эту функцию можно использовать примерно так:
>>> first(range(10))
0
>>> first(range(10), lambda i: i > 3)
4
Однако я не могу придумать хороший встроенный / однострочный, чтобы позволить мне это сделать. Я не особенно хочу копировать эту функцию, если мне не нужно. Есть ли встроенный способ получить первый элемент, соответствующий условию?
Ответы:
В Python 2.6 или новее:
Если вы хотите
StopIteration
быть поднятым, если соответствующий элемент не найден:Если вы хотите
default_value
(напримерNone
) быть возвращенным вместо:Обратите внимание, что в этом случае вам нужна дополнительная пара скобок вокруг выражения генератора - они нужны, когда выражение генератора не является единственным аргументом.
Я вижу, что большинство ответов решительно игнорируют
next
встроенные функции, и поэтому я предполагаю, что по какой-то таинственной причине они на 100% ориентированы на версии 2.5 и старше - без упоминания проблемы с Python-версией (но тогда я не вижу этого упоминания в ответы, в которых упоминаетсяnext
встроенная функция, поэтому я решил, что необходимо дать ответ сам - по крайней мере, проблема с «правильной версией» регистрируется таким образом ;-).В 2.5
.next()
метод итераторов немедленно повышается,StopIteration
если итератор немедленно завершается - т. Е. Для вашего случая использования, если ни один элемент в итерируемом не удовлетворяет условию. Если вам все равно (то есть вы знаете, что должен быть хотя бы один удовлетворительный элемент), тогда просто используйте.next()
(лучше всего для genexp, строка дляnext
встроенного в Python 2.6 и лучше).Если вы делаете уход, упаковка вещей в функции , как вы впервые указаны в вашем Q кажется лучшим, и в то время как реализация функции вы предложили просто отлично, можно альтернативно использовать
itertools
, вfor...: break
петлю, или genexp, илиtry/except StopIteration
как тело функции , как предложили различные ответы. Ни в одной из этих альтернатив нет особой выгоды, поэтому я бы остановился на совершенно простой версии, которую вы впервые предложили.источник
StopIteration
когда элемент не найденStopIteration
на самом деле не красиво. Лучше использовать метод.Как многоразовая, документированная и протестированная функция
Версия с аргументом по умолчанию
@zorf предложил версию этой функции, в которой вы можете иметь предопределенное возвращаемое значение, если итерация пуста или не содержит элементов, соответствующих условию:
источник
StopIteration
- это каноническое исключение "вне элементов" в python. Я не вижу проблемы с его выбросом. Я бы, вероятно, использовал значение по умолчанию «None», которое можно передать в качестве параметра по умолчанию функции.Черт, исключения!
я люблю этот ответ . Однако, поскольку
next()
возникаетStopIteration
исключение, когда нет элементов, я бы использовал следующий фрагмент, чтобы избежать исключения:Например,
Поднимет
StopIteration
исключение;источник
Подобно использованию
ifilter
, вы можете использовать выражение генератора:В любом случае, вы, вероятно, хотите поймать
StopIteration
, если ни один элемент не удовлетворяет вашему условию.Технически говоря, я полагаю, вы могли бы сделать что-то вроде этого:
Это позволило бы избежать создания
try/except
блока. Но это кажется неясным и оскорбительным для синтаксиса.источник
for foo in genex: break
- это просто способfoo = next(genex)
обойтись без ясного назначения и за исключением того, что будет вызвано, если операция не имеет смысла быть сжатой. Завершение работы с кодом ошибки вместо перехвата исключения - это обычно плохая вещь в Python.Наиболее эффективный способ в Python 3 - это одно из следующих действий (на похожем примере):
Со стилем «понимания» :
ПРЕДУПРЕЖДЕНИЕ : выражение работает также с Python 2, но в примере используется,
range
который возвращает итерируемый объект в Python 3 вместо списка, подобного Python 2 (если вы хотите создать итерируемый в Python 2, используйтеxrange
вместо этого).Обратите внимание, что выражение избегает создания списка в выражении понимания
next([i for ...])
, что приведет к созданию списка со всеми элементами перед фильтрацией элементов и к обработке всех опций вместо остановки итерации один разi == 1000
.С «функциональным» стилем:
ВНИМАНИЕ : Это не работает в Python 2, даже если заменить его
range
наxrange
тот, которыйfilter
создает список вместо итератора (неэффективно), аnext
функция работает только с итераторами.Значение по умолчанию
Как упоминалось в других ответах, вы должны добавить в функцию дополнительный параметр,
next
если хотите избежать исключения, возникающего при невыполнении условия.«функциональный» стиль:
стиль "понимания" :
С этим стилем вы должны окружить выражение понимания,
()
чтобы избежатьSyntaxError: Generator expression must be parenthesized if not sole argument
:источник
Я бы написал это
источник
i > 3
должно бытьx > 3
в вашем примереitertools
Модуль содержит функцию фильтра для итераторы. Первый элемент отфильтрованного итератора можно получить, вызвавnext()
его:источник
i
)filter
и (i
)map
могут иметь смысл для случаев, когда применяемые функции уже существуют, но в подобной ситуации имеет гораздо больше смысла просто использовать выражение генератора.Для более старых версий Python, где нет следующего встроенного:
источник
Используя
можно проверить состояние от значения первого элемента в the_iterable , и получить его индекс без необходимости оценивать все элементы в the_iterable .
Полное выражение для использования
Здесь first_index предполагает значение первого значения, указанного в выражении, рассмотренном выше.
источник
На этот вопрос уже есть отличные ответы. Я только добавляю свои два цента, потому что я приземлился здесь, пытаясь найти решение моей собственной проблемы, которая очень похожа на ОП.
Если вы хотите найти ИНДЕКС первого элемента, соответствующего критерию, с помощью генераторов, вы можете просто сделать:
источник
Вы также можете использовать
argwhere
функцию в Numpy. Например:i) Найдите первое «l» в «helloworld»:
II) Найти первое случайное число> 0,1
iii) Найти последнее случайное число> 0,1
источник
В Python 3:
В Python 2.6:
РЕДАКТИРОВАТЬ: Я думал, что это было очевидно, но, очевидно, нет: вместо
None
вас можно передать функцию (илиlambda
) с проверкой на условие:источник
Один лайнер:
Если вы не уверены, что какой-либо элемент будет действительным в соответствии с критериями, вы должны заключить это с,
try/except
так как это[0]
может вызватьIndexError
.источник