【问题标题】:Pythonic way for Zigzag Iterator?Zigzag Iterator 的 Pythonic 方式?
【发布时间】:2018-07-18 15:43:33
【问题描述】:

我在 Zigzag Iterator 上编程,它是通过以下方式迭代一个 2D 列表:

[1,4,7]
[2,5,8,9]
[3,6]

[1,2,3,4,5,6,7,8,9]

我实现了一个算法:

class ZigzagIterator:

    def __init__(self, vecs):

        self.vecs = []
        self.turns = 0
        for vec in vecs:
            vec and self.vecs.append(iter(vec))

    def next(self):
        try:
            elem = self.vecs[self.turns].next()
            self.turns = (self.turns+1) % len(self.vecs)
            return elem
        except StopIteration:
            self.vecs.pop(self.turns)
            if self.hasNext():
                self.turns %= len(self.vecs)

    def hasNext(self):
        return len(self.vecs) > 0

if __name__ == "__main__":
    s = ZigzagIterator([[1,4,7],[2,5,8,9],[3,6]])
    while s.hasNext():
        print s.next()

>>> 1 2 3 4 5 6 7 8 None None 9 None

我知道问题是因为我在每个列表的 next() 中再调用 1 次,然后我得到 3 次无。我可以通过使用 java 检查 Havenext 方法来解决此问题。我还可以在 python 中实现一个 hasext 迭代器。我的问题是如何以更 Pythonic 的方式解决这个问题,而不是用 Java 来思考它。

【问题讨论】:

    标签: python iterator


    【解决方案1】:

    这是itertools docs 中的循环方法。

    def roundrobin(*iterables):
        "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
        # Recipe credited to George Sakkis
        num_active = len(iterables)
        nexts = cycle(iter(it).__next__ for it in iterables)
        while num_active:
            try:
                for next in nexts:
                    yield next()
            except StopIteration:
                # Remove the iterator we just exhausted from the cycle.
                num_active -= 1
                nexts = cycle(islice(nexts, num_active))
    

    【讨论】:

      【解决方案2】:

      这可以使用itertools中的工具轻松构建:

      from itertools import zip_longest, chain
      
      sentinel = object()
      
      def zigzag(lists):
          return (
              value
              for value
              in chain.from_iterable(zip_longest(*lists, fillvalue=sentinel))
              if value is not sentinel
          )
      
      lists = [
          [1,4,7],
          [2,5,8,9],
          [3,6],
      ]
      
      print(list(zigzag(lists)))
      

      sentinel 的东西是必需的,所以None 值可以安全地曲折。 (这个值应该保证不会出现在原始列表中。)

      【讨论】:

        【解决方案3】:
        from itertools import chain, zip_longest
        print([i for i in chain.from_iterable(zip_longest([1,4,7], [2,5,8,9], [3,6])) if i is not None])
        

        这个输出:

        [1, 2, 3, 4, 5, 6, 7, 8, 9]
        

        【讨论】:

        • 这将丢失输入列表中的所有虚假值。
        • 确实如此。按照建议修复。
        【解决方案4】:

        对于 pythonic 解决方案,您需要实现迭代器协议,我希望这正是您正在寻找的。​​p>

        from itertools import chain, zip_longest
        
        
        class ZigZagIterator:
            def __init__(self, *lists):
                self.elements = chain(*zip_longest(*lists))
        
            def __iter__(self):
                for num in self.elements:
                    if num is not None:
                        yield num
        
        
        zig = ZigZagIterator([1, 4, 7], [2, 5, 8, 9], [3, 6])
        
        for num in zig:
            print(num)
        

        如果你真的想使用has_nextnext 那么

        from itertools import chain, zip_longest
        
        
        class ZigZagIterator:
            def __init__(self, *lists):
                elements = chain(*zip_longest(*lists))
                self.elements = filter(lambda x: x is not None, elements)
        
            def has_next(self):
                try:
                    self.next_value = next(self.elements)
                except StopIteration:
                    return False
                return True
        
            def next(self):
                return self.next_value
        
        
        zig = ZigZagIterator([1, 4, 7], [2, 5, 8, 9], [3, 6])
        
        while zig.has_next():
            print(zig.next())
        

        【讨论】:

        • hasnext 也是问题所必需的,因为它最终想要调用 while it.hasnext()
        猜你喜欢
        • 2011-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-27
        • 2016-06-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多