Питонический способ для длины генератора не менее 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
, Это означает, что если при оценке генератора есть побочные эффекты, они будут срабатывать при проверке длины.