简体   繁体   English

Zigzag Iterator的Pythonic方式?

[英]Pythonic way for Zigzag Iterator?

I'm programming onto Zigzag Iterator, it is to iterate a 2D list in following way: 我正在编写Zigzag Iterator,它是以下列方式迭代2D列表:

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

to

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

I implemented an algorithem: 我实现了一个算法:

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

I know the problem is because I call 1 more time next() of each list, then I get 3 None. 我知道问题是因为我再次调用每个列表的next(),然后我得到3无。 I could resolve this issue by checking the hasnext method with java. 我可以通过使用java检查hasnext方法来解决此问题。 I can also implement a hasnext Iterator in python. 我也可以在python中实现一个hasnext Iterator。 My questions is how I can solve this problem in a more pythonic way rather than thinking it in Java. 我的问题是如何以更加pythonic的方式解决这个问题,而不是用Java思考它。

This is the round robin recipe in the itertools docs . 这是itertools文档中的循环配方。

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

This can be easily built with tools in itertools : 这可以使用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)))

The sentinel stuff is needed so None values can be safely zigzagged over. 需要sentinel东西,所以None值可以安全地曲折。 (It's a value that's supposed to be guaranteed to not show up in the original lists.) (这是一个应该保证不会出现在原始列表中的值。)

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

This outputs: 这输出:

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

For pythonic solution you need to implement the iterator protocol, I hope this is exactly what you were looking for. 对于pythonic解决方案,您需要实现迭代器协议,我希望这正是您所寻找的。

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)

If you really want to use has_next and next then 如果你真的想使用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())

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 pythonic方式:迭代器链接和资源管理 - pythonic way: Iterator chaining and resource management 消耗迭代器的最快(最Pythonic)方式 - Fastest (most Pythonic) way to consume an iterator 从特定索引启动迭代器的 Pythonic 方式 - Pythonic way to start an iterator from an specific index 在列表中解压缩迭代器的Python方法 - Pythonic way to unpack an iterator inside of a list 允许整数索引或索引迭代器的正确pythonic方法? - proper pythonic way to allow integer index or a iterator of indexes? 用一个迭代器将列表分成两部分的Python方式 - Pythonic way of splitting loop over list in two parts with one iterator 当前几个值很特殊时,通过迭代器循环的Python方式是什么? - What's the Pythonic way to loop through an iterator when the first few values are special? 将键/值对的列表(或其他迭代器)添加到dict的Python方法是什么? - What's a Pythonic way to add a list (or other iterator) of key/value pairs to a dict? 使用 multiprocessing.Pool 同时附加到迭代器的 map 的 Pythonic 方式是什么? - What's the Pythonic way to map with multiprocessing.Pool while also appending to the iterator? 在for循环体中使用迭代器是安全的和pythonic吗? - Is it safe and pythonic to consume the iterator in the body of a for loop?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM