Найти последний элемент в строке, который соответствует критерию - PullRequest
0 голосов
/ 28 октября 2019

В дополнение к этому вопросу " Получить первый элемент из итерируемого, который соответствует условию " Мне нужен элемент один перед первым соответствием. Или полностью эквивалентный: последний элемент в строке, который соответствует критерию. Например, если мне нужно последнее простое число перед первым не простым числом в этом списке [2, 3, 4, 5, 6, 7, 8, 9], ответ будет 3. Если такого элемента нет, результатом может быть None, исключение или значение по умолчанию.

Простое решение:

result = None
for x in numbers:
    if is_prime(x):
        result = x
    else:
        break

Есть ли простой однострочный, который решает задачу?

Ответы [ 2 ]

2 голосов
/ 28 октября 2019

Вы можете использовать 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]
2 голосов
/ 28 октября 2019

Не уверен, что есть более простой способ. Мой подход требует itertools.takewhile.

  1. Использование itertools.takewhile для прекращения итерации после того, как условие больше не выполняется, для создания списка простых чисел допоявляется первое не простое число, то есть [2, 3]
  2. Затем используйте list[-1], чтобы получить последний элемент списка.
  3. Если список пуст, используйте (list or [None])[-1], чтобы он возвращал None
import itertools
result = ([x for x in itertools.takewhile(lambda n: is_prime(n), numbers)] or [None])[-1]

collection.deque ()

from collections import deque
result = (deque((itertools.takewhile(lambda n: is_prime(n), numbers)), maxlen=1) or [None]).pop()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...