最后使用附加项获取成对迭代器

时间:2022-03-03 10:16:55

The goal: e.g. given finite iterator p0, p1, ..., pn turn into (p0, p1), (p1, p2), ..., (pn-1, pn), (pn, None) — iterator through pairs of consecutive items with special last item.

目标:例如给定有限迭代器p0,p1,...,pn变为(p0,p1),(p1,p2),...,(pn-1,pn),(pn,无) - 迭代器通过成对的连续项特别的最后一项。

pairwise() function exists in the documentation as example of itertools usage:

pairwise()函数作为itertools用法的例子存在于文档中:

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)

But I want additionally add yet another item to the end of iterator (if it is finite) with some default value for the second element of pair (e.g., None).

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

How to efficiently implement this additional functionality?

如何有效地实现这个附加功能?

3 个解决方案

#1


6  

Using itertools.zip_longest:

使用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)

When one of the input iterators runs out, zip_longest pads it with a filler value, which defaults to None.

当其中一个输入迭代器用完时,zip_longest会使用填充值填充它,默认值为None。

#2


1  

As for adding (sn, None) at the end, as user2357112 already answered, you can just use zip_longest so one already exhausted iterator is not stopping the whole sequence (so the a iterator can still yield the last element).

至于在末尾添加(sn,None),正如user2357112已经回答的那样,你可以使用zip_longest,因此一个已经耗尽的迭代器不会停止整个序列(因此迭代器仍然可以产生最后一个元素)。

For all other situations, e.g. if you want to add further elements at the end, you can just make a generator function itself. All the itertools function are already lazy generators, only producing new results when you request the next element in the result, and you can easily consume those from within a generator.

对于所有其他情况,例如如果你想在最后添加更多的元素,你可以自己创建一个生成器函数。所有itertools函数都是惰性生成器,只有在请求结果中的下一个元素时才会生成新结果,并且您可以轻松地从生成器中使用它们。

Let’s say, you need pairwise to yield a sentinel value (None, None) at the end, then you could simply yield the results from zip_longest and then yield another item:

比方说,你需要成对地在结尾产生一个标记值(无,无),然后你可以简单地从zip_longest产生结果然后产生另一个项目:

def example (iterable):
    a, b = tee(iterable)
    next(b, None)
    yield from zip_longest(a, b)
    yield (None, None)

The yield from syntax actually came with Python 3.3. For earlier versions, especially Python 2, you would need to do that manually by looping over the items and yielding them again:

语法的收益实际上来自Python 3.3。对于早期版本,尤其是Python 2,您需要通过循环遍历项目并再次生成它们来手动执行此操作:

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

#3


0  

You can create a generator:

您可以创建一个生成器:

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

Results:

结果:

>>> 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')]

For an infinite iterable:

对于无限可迭代:

>>> 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)

#1


6  

Using itertools.zip_longest:

使用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)

When one of the input iterators runs out, zip_longest pads it with a filler value, which defaults to None.

当其中一个输入迭代器用完时,zip_longest会使用填充值填充它,默认值为None。

#2


1  

As for adding (sn, None) at the end, as user2357112 already answered, you can just use zip_longest so one already exhausted iterator is not stopping the whole sequence (so the a iterator can still yield the last element).

至于在末尾添加(sn,None),正如user2357112已经回答的那样,你可以使用zip_longest,因此一个已经耗尽的迭代器不会停止整个序列(因此迭代器仍然可以产生最后一个元素)。

For all other situations, e.g. if you want to add further elements at the end, you can just make a generator function itself. All the itertools function are already lazy generators, only producing new results when you request the next element in the result, and you can easily consume those from within a generator.

对于所有其他情况,例如如果你想在最后添加更多的元素,你可以自己创建一个生成器函数。所有itertools函数都是惰性生成器,只有在请求结果中的下一个元素时才会生成新结果,并且您可以轻松地从生成器中使用它们。

Let’s say, you need pairwise to yield a sentinel value (None, None) at the end, then you could simply yield the results from zip_longest and then yield another item:

比方说,你需要成对地在结尾产生一个标记值(无,无),然后你可以简单地从zip_longest产生结果然后产生另一个项目:

def example (iterable):
    a, b = tee(iterable)
    next(b, None)
    yield from zip_longest(a, b)
    yield (None, None)

The yield from syntax actually came with Python 3.3. For earlier versions, especially Python 2, you would need to do that manually by looping over the items and yielding them again:

语法的收益实际上来自Python 3.3。对于早期版本,尤其是Python 2,您需要通过循环遍历项目并再次生成它们来手动执行此操作:

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

#3


0  

You can create a generator:

您可以创建一个生成器:

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

Results:

结果:

>>> 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')]

For an infinite iterable:

对于无限可迭代:

>>> 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)