Получите первый объект от повторяемого, которое соответствует условию

Я хотел бы получить первый объект из списка, соответствующего условию. Важно, чтобы получающийся метод не обработал весь список, который мог быть довольно большим. Например, следующая функция соответствует:

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

Однако я не могу думать о пользе, встроенной / острота, чтобы позволить мне сделать это. Я особенно не хочу копировать эту функцию вокруг, если я не имею к. Существует ли встроенный способ получить первый объект, соответствующий условию?

263
задан davidism 8 November 2017 в 07:50
поделиться

6 ответов

В Python 2.6 или выше:

Если вы хотите, чтобы StopIteration вызывался, если соответствующий элемент не найден:

next (x вместо x в the_iterable, если x> 3)

Если вы хотите, чтобы вместо этого возвращалось default_value (например, None ):

next ((x for x in the_iterable, если x> 3), default_value)

Обратите внимание, что в этом случае вам понадобится дополнительная пара круглых скобок вокруг выражения генератора - они необходимы всегда, когда выражение генератора - не единственный аргумент.

Я вижу, что большинство ответов решительно игнорируют встроенный next , и поэтому я предполагаю, что по какой-то загадочной причине они на 100% сосредоточены на версии 2.5 и старше - без упоминания проблемы версии Python (но тогда я не вижу упоминания в ответах, что действительно упоминает встроенный следующий ], поэтому я счел необходимым дать ответ сам - по крайней мере, проблема с "правильной версией" таким образом фиксируется ;-).

В версии 2.5 метод итераторов .next () немедленно вызывает StopIteration , если итератор немедленно завершает свою работу, т. Е. Для вашего варианта использования, если ни один элемент в итераторе не удовлетворяет условие. Если вам все равно (например, вы знаете, что там должен быть хотя бы один удовлетворительный элемент), просто используйте .next () (лучше всего на genexp, строка для next встроен в Python 2.6 и выше).

Если вы заботитесь, то лучше всего будет заключить что-то в функцию, как вы впервые указали в Q, и хотя предложенная вами реализация функции вполне хороша, вы также можете использовать itertools , for ...: break цикл, или genexp, или try / except StopIteration в качестве тела функции, как предлагалось в различных ответах. Ни в одной из этих альтернатив нет особой добавленной стоимости, поэтому я бы выбрал совершенно простую версию, которую вы впервые предложили.

410
ответ дан 23 November 2019 в 02:33
поделиться

Oneliner:

thefirst = [i for i in range(10) if i > 3][0]

Если вы не уверены, что какой-либо элемент будет допустимым в соответствии с критериями, вы должны заключить его в try / except , поскольку это [0] может вызвать IndexError .

-3
ответ дан 23 November 2019 в 02:33
поделиться

Аналогично использованию ifilter, вы можете использовать выражение-генератор:

>>> (x for x in xrange(10) if x > 5).next()
6

В любом случае, вы, вероятно, захотите поймать StopIteration на случай, если ни один элемент не удовлетворяет вашему условию.

Технически говоря, я полагаю, вы можете сделать что-то вроде этого:

>>> foo = None
>>> for foo in (x for x in xrange(10) if x > 5): break
... 
>>> foo
6

Это позволит избежать необходимости делать блок try/except. Но это кажется несколько неясным и оскорбительным для синтаксиса.

13
ответ дан 23 November 2019 в 02:33
поделиться

Модуль itertools содержит функцию фильтрации для итераторов. . Первый элемент отфильтрованного итератора можно получить, вызвав для него next () :

from itertools import ifilter

print ifilter((lambda i: i > 3), range(10)).next()
6
ответ дан 23 November 2019 в 02:33
поделиться

Для более старых версий Python, в которых не существует следующей встроенной программы. :

(x for x in range(10) if x > 3).next()
6
ответ дан 23 November 2019 в 02:33
поделиться

Я бы написал так

next(x for x in xrange(10) if x > 3)
6
ответ дан 23 November 2019 в 02:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: