python - 重复可迭代对象元素的迭代器

python - Iterator which duplicates elements of iterable object

我需要编写一个函数 duplicate(it),其中 returns 迭代器复制可迭代 it 的元素。示例:如果 it = [1, 2, 3]list(duplicate(it)) == [1, 1, 2, 2, 3, 3]。我尝试为列表实现 DoubleIterator class 和 duplicate(it) 函数(不确定在这种情况下 DoubleIterator 的正确实现方式,欢迎提供有用的建议):

class DoubleIterator():
    def __init__(self, data):
        self.data = data
        self.pos = 0
        self.limit = len(data)
        self.dup = 0

    def next(self): # __next__ for Python 3
        if self.dup != 0 and self.dup % 2 == 0:
            self.pos = self.pos + 1
        if self.pos < self.limit:
            self.dup += 1
            return self.data[self.pos]
        else:
            raise StopIteration

    def __iter__(self):
        return self

def duplicate(it):
    itr = DoubleIterator(it)
    return iter(itr)

它适用于 list(duplicate(it)) == [1, 1, 2, 2, 3, 3] 示例和类似的东西:

dup = duplicate([1, 2, 3])
print next(dup) #1
print next(dup) #1
print next(dup) #2
print next(dup) #2
print next(dup) #3
print next(dup) #3

但是此功能的任务测试之一是 dup = duplicate(iter([1, 2, 3])),它给出了一个错误:TypeError: object of type 'listiterator' has no len()。我应该如何以正确的方式实现 duplicate 函数和迭代器 class?

我会做一个发电机

def duplicate(it,n=2):
    for x in it:
        for _ in range(n):
            yield x

你把事情复杂化了一点。您需要做的就是获取下一个元素并 yield 两次。您确实需要将输入视为迭代器,而不是序列。只有像列表这样的序列才有长度并且可以被索引,迭代器所能做的就是给你下一个值直到它耗尽。

对于 class-based 迭代器,这意味着您需要存储要重复的元素,以便对 next() 的每个其他调用都可以生成该存储的值,而其他调用则获取下一个元素来自输入迭代器:

class DoubleIterator:
    _sentinel = object()

    def __init__(self, iterator):
        self._data = iter(iterator)
        self._repeat = self._sentinel

    def next(self): # __next__ for Python 3
        if self._repeat is self._sentinel:
            # get next element to yield, can raise StopIteration
            self._repeat = next(self._data)
            return self._repeat
        # repeat last element
        element = self._repeat
        self._repeat = self._sentinel
        return element

    def __iter__(self):
        return self

我使用了一个独特的哨兵来确保支持输入迭代器中的 None 值,并且我在输入迭代器上调用了 iter() 以确保我们始终可以调用 next() 在那个对象上。

但是,更容易在这里只写一个生成器函数,并产生每个元素两次:

def double_iterator(iterator):
    for elem in iterator:
        yield elem
        yield elem

你可以用循环进一步推广,但如果你只需要将元素加倍,我会坚持使用更简单的双 yield.