Питонический способ для длины генератора не менее n

Какой способ Pythonic проверить, является ли длина итераблей хотя бы n?

Это мой подход:

import itertools

def is_iterable_longer_than(iterable, n):
    return n <= len(itertools.islice(iterable, n))

есть что-нибудь получше?

РЕДАКТИРОВАТЬ:

Я готов потреблять итеративное, даже если оно может быть оценено только один раз.

Как уже указывалось выше, есть ошибка. Так должно быть:

    return n <= len(list(itertools.islice(iterable, n)))

2 ответа

Решение

Там нет общего пути. Ваш даже не работает

>>> def is_iterable_longer_than(iterable, n):
...     return n <= len(itertools.islice(iterable, n))
...
>>> is_iterable_longer_than([], 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in is_iterable_longer_than
TypeError: object of type 'itertools.islice' has no len()

Единственный способ определить, имеет ли итерация хотя бы n объекты в нем, чтобы перебрать его, пока вы не получите n объекты или закончились. К сожалению, некоторые итерации могут повторяться только один раз. Если вам не нужно использовать содержимое итерируемого, вы можете сделать это:

def is_iterable_longer_than(iterable, n):
    return n == sum(1 for _ in itertools.islice(iterable, n))

Если вам нужно использовать содержимое итерируемого, вы можете создать еще один итерируемый, похожий на оригинал:

def is_iterable_longer_than(iterable, n):
    iter1, iter2 = itertools.tee(iterable)
    return sum(1 for _ in itertools.islice(iter1, n)) == n, iter2

Пока мы на этом, мы могли бы также попробовать lenНа всякий случай это работает:

def is_iterable_longer_than(iterable, n):
    iter1, iter2 = itertools.tee(iterable)
    try:
        return len(iterable) >= n, iter2
    except TypeError:
        return sum(1 for _ in itertools.islice(iter1, n)) == n, iter2

Это зависит от того, готовы ли вы оценить генератор или нет.

Если это так, это тривиально:

def gen_length_was_at_least_n(gen, n):
    return n == sum(1 for _ in itertools.islice(gen, n))

Если нет, значит, вы застряли, если только вы не захотите оценить его, но сохраните значения в буфере с помощью tee:

gen, extra = itertools.tee(gen)
if gen_length_was_at_least_n(extra):
    # ... do something with gen

Обратите внимание, что это частично оценивает исходный итератор; он просто хранит значения и передает их через новый генератор, возвращенный из tee, Это означает, что если при оценке генератора есть побочные эффекты, они будут срабатывать при проверке длины.

Другие вопросы по тегам