获得具有额外项的成对迭代器

5
目标: 给定有限迭代器p0,p1,...,pn,将其转换为(p0,p1),(p1,p2),...,(pn-1,pn),(pn,None) - 通过一系列连续项的对进行迭代,最后一项是特殊项。 pairwise()函数在文档中作为itertools使用示例存在。
def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)

但我还想在迭代器的末尾添加另一个项目(如果它是有限的),并为二元组的第二个元素添加一些默认值(例如 None )。

如何有效地实现这种额外的功能?

3个回答

10
使用 itertools.zip_longest
def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return zip_longest(a, b)

当输入迭代器之一用尽时,zip_longest 会使用一个填充值来添加内容,这个填充值默认为 None


2
关于在结尾添加`(sn, None)`,如用户user2357112已经回答的那样,您可以使用`zip_longest`,这样一个已经用尽的迭代器不会停止整个序列(因此迭代器`a`仍然可以产生最后一个元素)。
对于其他所有情况,例如如果您想在结尾添加更多元素,您可以创建一个生成器函数本身。所有`itertools`函数都是惰性生成器,只有在请求结果中的下一个元素时才会产生新的结果,并且您可以轻松地从生成器内部消耗这些结果。
假设您需要`pairwise`在结尾产生一个哨兵值`(None, None)`,那么您可以简单地从`zip_longest`中产生结果,然后再产生另一个项:
def example (iterable):
    a, b = tee(iterable)
    next(b, None)
    yield from zip_longest(a, b)
    yield (None, None)
< p > yield from 语法实际上是在 Python 3.3 中引入的。对于早期版本,特别是 Python 2,您需要手动循环遍历项目并再次进行 yield:

def example (iterable):
    a, b = tee(iterable)
    next(b, None)
    for x in zip_longest(a, b):
        yield x
    yield (None, None)

0
你可以创建一个生成器:
def pairwise(iterable, additional=None):
    iterable = iter(iterable)
    first, second = next(iterable), next(iterable)
    while 1:
        yield first,second
        try:
            first,second = second, next(iterable)
        except TypeError:
            yield second, additional
            break

结果:

>>> list(pairwise([1,2,3], 'a'))
[(1, 2), (2, 3), (3, 'a')]
>>> list(pairwise('abc', 'a'))
[('a', 'b'), ('b', 'c'), ('c', 'a')]
>>> list(pairwise('abcd', 'a'))
[('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'a')]

对于一个无限可迭代对象:

>>> a = pairwise(infi(), 6)
>>> for i in range(10):
...     print(next(a))
...
(0, 1)
(1, 2)
(2, 3)
(3, 0)
(0, 1)
(1, 2)
(2, 3)
(3, 0)
(0, 1)
(1, 2)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接