从一个可迭代对象中,我想生成其前缀的可迭代对象(包括原始可迭代对象本身)。
for prefix in prefixes(range(5)):
print(tuple(prefix))
应该导致
(0,)
(0, 1)
(0, 1, 2)
(0, 1, 2, 3)
(0, 1, 2, 3, 4)
或在
()
(0,)
(0, 1)
(0, 1, 2)
(0, 1, 2, 3)
(0, 1, 2, 3, 4)
和
for prefix in prefixes('Hello'):
print(''.join(prefix))
应该导致
H
He
Hel
Hell
Hello
或在
H
He
Hel
Hell
Hello
(空前缀是否是结果的一部分对我来说并不重要,内部或外部结果迭代的确切类型也不重要。)
我能够设计出几种方法来实现这一点,但都觉得至少有点笨拙:
使用切片和 len:
(如果 iterable 是一个序列则有效)
def prefixes(seq):
for i in range(len(seq)):
yield seq[:i + 1]
或使用列表理解:
def prefixes(seq):
return [seq[:i + 1] for i in range(len(seq))]
...或生成器表达式
def prefixes(seq):
return (seq[:i + 1] for i in range(len(seq)))
(这些不会产生空前缀。要包含它,请在上述任何一个中替换[i + 1]
为 just[i]
和range(len(seq))
by range(len(seq) + 1)
。)
这些感觉很笨重:
- 因为它们不适用于所有类型的可迭代输入
- 因为需要
+ 1
抵消 - 调用
range
某len
事(虽然enumerate
不会在这里变得更好)
使用连接
def prefixes(iterable):
result = ()
for elem in iterable:
result += (elem,)
yield result
(不包括空前缀。这可以通过在-loopresult
之前产生一次来更改。)for
或使用itertools.accumulate
from itertools import accumulate as acc
def prefixes(iterable):
return acc(iterable, lambda t, elem: t + (elem,), initial=())
或者更具可读性:
from itertools import accumulate
def _append(iterable, elem):
return iterable + (elem,)
def prefixes(iterable):
return accumulate(iterable, _append, initial=())
(这两个包括空前缀。如果不需要,请删除它。)
由于需要将元素打包到长度为一的容器中,以便将它们连接到现有的容器,因此这些感觉很笨重。
更优雅的解决方案?
我觉得我必须从itertools
,中遗漏一些东西functools
,operator
或者more-itertools
这将允许稍微甚至明显不那么笨重的实现。我的意思是,这与它非常相似more_itertools.powerset
,只是它的一个非常具体的子集。