代码之家  ›  专栏  ›  技术社区  ›  st_dec

python—复制iterable对象元素的迭代器

  •  2
  • st_dec  · 技术社区  · 7 年前

    我需要写一个函数 duplicate(it) 返回iterable的迭代器复制元素 it 。示例:如果 it = [1, 2, 3] 然后 list(duplicate(it)) == [1, 1, 2, 2, 3, 3] 。我试图实施 DoubleIterator 类别和 复制(it) 用于列表的函数(不确定 双迭代器 在这种情况下,欢迎提供有用的建议):

    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)
    

    它适用于 列表(重复(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 函数和迭代器类是否正确?

    2 回复  |  直到 7 年前
        1
  •  4
  •   Smart Manoj AlexP    7 年前

    我会把它当成发电机

    def duplicate(it,n=2):
        for x in it:
            for _ in range(n):
                yield x
    
        2
  •  2
  •   Martijn Pieters    7 年前

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

    对于基于类的迭代器,这意味着您需要存储要重复的元素,以便每次调用 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() 输入iterable以确保我们始终可以调用 下一个() 在那个物体上。

    然而,它是 容易得多 只需在此处编写一个生成器函数,并两次生成每个元素:

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

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