Вы можете использовать zip
и islice
для создания итератора с его собственным «будущим», доступным для него.
next(
filter(
lambda pair: isprime(pair[1]), # The predicate applied to a pair
zip(xs, islice(xs, 1, None)) # The iterator and its 'future'
),
(None, None) # A default pair in case no matches are found
)[0] # Retrieve the 'current' entry from the matching pair
На каждом шаге у вас есть пара, которую вы можете представить как (present, future)
и предикат будет применен к future
. В конце мы распаковываем present
, который представляет последнюю несоответствующую запись в итераторе.
Обратите внимание, что эта реализация, как представлено, не возвращает последнюю запись в списке, потому что по своей сути, еслиВы застегиваете [a, b, c]
против его собственной сдвинутой версии, в результате вы получаете один короче другого. Вы можете использовать zip_longest
(из itertools
), чтобы преодолеть это, но вам нужно обработать fillvalue
(обычно None
) в вашем предикате.
Как отмечено вкомментарий, это не работает для генераторов, потому что он будет использовать генератор. Использование сгиба (reduce
в Python), однако, становится проще. Во-первых, в более «питоническом» представлении функция выглядит примерно так:
def fold(hist, cur):
stop, prev = hist
if stop:
return hist
if isprime(cur):
return (True, prev)
return (False, cur)
Первый элемент кортежа служит маркером «остановки», а второй - нашей «иглой». Вы можете использовать это с уменьшением, таким образом:
reduce(fold, xs, (False, None))[1]
Это не совсем «один вкладыш», но мы можем сжать его в lambda
:
reduce(lambda z, x: (z if z[0] else ((1, z[1]) if isprime(x) else (0, x))), xs, (0, None))[1]