生成器长度至少为n的Pythonic方式

时间:2014-01-04 01:57:37

标签: python iterable

检查迭代的长度是否至少n的Pythonic方法是什么?

这是我的方法:

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 个答案:

答案 0 :(得分:3)

没有一般方法。你甚至不工作:

>>> 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个对象或用完为止。不幸的是,一些迭代只能迭代一次。如果您不关心使用iterable的内容,可以这样做:

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

如果需要使用iterable的内容,可以创建另一个看起来像原始的迭代:

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

答案 1 :(得分:2)

这取决于你是否愿意评估发电机。

如果你是,那很简单:

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返回的新生成器为它们提供服务。这意味着如果评估发电机有副作用,那么在进行长度检查时会触发它们。