[英]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_next
和next
再
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.