如何知道生成的序列最多一定长度
How to know a generated sequence is at most a certain length
我想知道生成的序列是否少于 2 个条目。
>>> def sequence():
... for i in xrange(secret):
... yield i
我低效的方法是创建一个列表,并测量它的长度:
>>> secret = 5
>>> len(list(sequence())) < 2
True
显然,这会消耗整个生成器。
在我的真实案例中,生成器可能正在穿越一个大型网络。我想在不消耗整个生成器或构建大列表的情况下进行检查。
有个recipe in the itertools documentation:
def take(n, iterable):
"Return first n items of the iterable as a list"
return list(islice(iterable, n))
这只构建一个最大长度的列表n
,更好。
所以我可以说:
>>> len(take(2, sequence()) < 2
是否有更 pythonic、更有效的方法来做到这一点?
从 Python 3.4 开始,生成器可以实现 length hint. If a generator implements this it'll be exposed through the object.__length_hint__()
method.
您可以使用 operator.length_hint()
function 进行测试。
如果不可用,您唯一的选择就是消耗元素,而使用take()
配方是最有效的方法:
from operator import length_hint
from itertools import chain
elements = []
length = length_hint(gen, None)
if length is None:
elements = list(take(2, gen))
length = len(elements)
if length >= 2:
# raise an error
# use elements, then gen
gen = chain(elements, gen)
使用take
的解决方案使用islice
,构建一个列表并取其长度:
>>> from itertools import islice
>>> len(list(islice(sequence(), 2))
2
为了避免创建列表,我们可以使用 sum
:
>>> sum(1 for _ in islice(sequence(), 2)
2
这大约需要 70% 的时间:
>>> timeit('len(list(islice(xrange(1000), 2)))', 'from itertools import islice')
1.089650974650752
>>> timeit('sum(1 for _ in islice(xrange(1000), 2))', 'from itertools import islice')
0.7579448552500647
总结一下:
>>> def at_most(n, elements):
... return sum(1 for _ in islice(elements, n + 1)) <= n
>>> at_most(5, xrange(5))
True
>>> at_most(2, xrange(5))
False
我想知道生成的序列是否少于 2 个条目。
>>> def sequence():
... for i in xrange(secret):
... yield i
我低效的方法是创建一个列表,并测量它的长度:
>>> secret = 5
>>> len(list(sequence())) < 2
True
显然,这会消耗整个生成器。
在我的真实案例中,生成器可能正在穿越一个大型网络。我想在不消耗整个生成器或构建大列表的情况下进行检查。
有个recipe in the itertools documentation:
def take(n, iterable):
"Return first n items of the iterable as a list"
return list(islice(iterable, n))
这只构建一个最大长度的列表n
,更好。
所以我可以说:
>>> len(take(2, sequence()) < 2
是否有更 pythonic、更有效的方法来做到这一点?
从 Python 3.4 开始,生成器可以实现 length hint. If a generator implements this it'll be exposed through the object.__length_hint__()
method.
您可以使用 operator.length_hint()
function 进行测试。
如果不可用,您唯一的选择就是消耗元素,而使用take()
配方是最有效的方法:
from operator import length_hint
from itertools import chain
elements = []
length = length_hint(gen, None)
if length is None:
elements = list(take(2, gen))
length = len(elements)
if length >= 2:
# raise an error
# use elements, then gen
gen = chain(elements, gen)
使用take
的解决方案使用islice
,构建一个列表并取其长度:
>>> from itertools import islice
>>> len(list(islice(sequence(), 2))
2
为了避免创建列表,我们可以使用 sum
:
>>> sum(1 for _ in islice(sequence(), 2)
2
这大约需要 70% 的时间:
>>> timeit('len(list(islice(xrange(1000), 2)))', 'from itertools import islice')
1.089650974650752
>>> timeit('sum(1 for _ in islice(xrange(1000), 2))', 'from itertools import islice')
0.7579448552500647
总结一下:
>>> def at_most(n, elements):
... return sum(1 for _ in islice(elements, n + 1)) <= n
>>> at_most(5, xrange(5))
True
>>> at_most(2, xrange(5))
False