使用 itertools.cycle() 循环遍历多个列表
cycle through multiple list using itertools.cycle()
我有一个服务器列表。每个服务器上都有一个名称列表。
示例:
server1 = ['a','b','c']
server2 = ['d','e','f']
server3 = ['g','h','i']
我想迭代每个服务器名称而不是每个服务器。例如在 server1
中选择 'a'
后,移动到 'd'
(而不是 'b'
)等等。如果我要使用 itertools.cycle()
,我是否必须创建一个服务器列表来循环?我的预期结果是 ['a','d','g','b','e','h','c','f','i']
。你能给我一个关于如何在多个列表中循环的简单例子吗?
试试这个:
from itertools import cycle
for k in cycle([j for i in zip(server1,server2,server3) for j in i]):
print(k)
#do you operations
a
d
g
b
...
但是关心这提供了无限循环
所以最好这样做:
c = cycle([j for i in zip(server1,server2,server3) for j in i])
>>>next(c)
a
>>>next(c)
b
....
您可以使用 zip
and reduce
内置函数(在 python3 functools.reduce
中):
>>> list_of_servers=[server1,server2,server3]
>>> s=reduce(lambda x,y:x+y,zip(*list_of_servers))
>>> s
('a', 'd', 'g', 'b', 'e', 'h', 'c', 'f', 'i')
或者对于长列表,您可以使用 itertools.chain
代替 reduce()
来连接 return 生成器的子列表:
>>> list(chain(*zip(*[server1,server2,server3])))
['a', 'd', 'g', 'b', 'e', 'h', 'c', 'f', 'i']
注意如果你想迭代你的结果,你不必在chain
的结果上使用list
。你可以做类似的事情:
for element in chain(*zip(*[server1,server2,server3])):
#do stuff
前面食谱的基准测试:
#reduce()
:~$ python -m timeit "server1 = ['a','b','c'];server2 = ['d','e','f'];server3 = ['g','h','i'];reduce(lambda x,y:x+y,zip(*[server1,server2,server3]))"
1000000 loops, best of 3: 1.11 usec per loop
#itertools.chain()
:~$ python -m timeit "server1 = ['a','b','c'];server2 = ['d','e','f'];server3 = ['g','h','i'];from itertools import chain;chain(*zip(*[server1,server2,server3]))"
100000 loops, best of 3: 2.02 usec per loop
请注意,如果您不将服务器放在列表中,速度会更快:
:~$ python -m timeit "server1 = ['a','b','c'];server2 = ['d','e','f'];server3 = ['g','h','i'];reduce(lambda x,y:x+y,zip(server1,server2,server3))"
1000000 loops, best of 3: 0.98 usec per loop
这个工作正常:
>>> from itertools import chain, islice, izip, cycle
>>> list(islice(cycle(chain.from_iterable(izip(server1, server2, server3))), 0, 18))
['a', 'd', 'g', 'b', 'e', 'h', 'c', 'f', 'i', 'a', 'd', 'g', 'b', 'e', 'h', 'c', 'f', 'i']
请注意,list
和 islice
仅用于演示目的,以显示内容并防止无限输出...
现在,如果你有不等长的列表,它会变得更有趣。然后 izip_longest
将成为您的朋友,但此时可能值得一个功能:
import itertools
def cycle_through_servers(*server_lists):
zipped = itertools.izip_longest(*server_lists, fillvalue=None)
chained = itertools.chain.from_iterable(zipped)
return itertools.cycle(s for s in chained if s is not None)
演示:
>>> from itertools import islice
>>> server3 = ['g', 'h', 'i', 'j']
>>> list(islice(cycle_through_servers(server1, server2, server3), 0, 20))
['a', 'd', 'g', 'b', 'e', 'h', 'c', 'f', 'i', 'j', 'a', 'd', 'g', 'b', 'e', 'h', 'c', 'f', 'i', 'j']
我们也可以使用 itertools.chain.from_iterable()
比较快。
import itertools
server1 = ['a','b','c']
server2 = ['d','e','f']
server3 = ['g','h','i']
print list(itertools.chain.from_iterable(zip(server1,server2,server3)))
结果:
['a', 'd', 'g', 'b', 'e', 'h', 'c', 'f', 'i']
from itertools import chain
for s in chain(*zip(server1, server2, server3)):
# do work
您可以使用链:
import itertools
server1 = ['a','b','c']
server2 = ['d','e','f']
server3 = ['g','h','i']
all_servers = [server1, server2, server3]
out_list = [s_name for a in itertools.chain(zip(*all_servers)) for s_name in a]
print(out_list)
#['a', 'd', 'g', 'b', 'e', 'h', 'c', 'f', 'i']
或更短:
out_list = list(itertools.chain.from_iterable(zip(*all_servers)))
standard library documentation 在 itertools
中将此功能作为配方提供。
def roundrobin(*iterables):
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
# Recipe credited to George Sakkis
pending = len(iterables)
nexts = cycle(iter(it).next for it in iterables)
while pending:
try:
for next in nexts:
yield next()
except StopIteration:
pending -= 1
nexts = cycle(islice(nexts, pending))
即使迭代器的长度不均匀,此代码也能正常工作,当较短的迭代器用完时循环遍历剩余的迭代器。这可能与您的用例相关,也可能不相关。
使用 chain
你可以简单地这样做:
from itertools import chain, izip
server1 = [1, 2]
server2 = [3, 4]
server3 = [4, 5]
print list(chain(*izip(server1, server2, server3))) # [1, 3, 4, 2, 4, 5]
或者您可以使用 chain.from_iterable
,它需要一个本身生成迭代器的可迭代对象。
在你的情况下 zip
是可迭代的,它以元组的形式生成迭代器:
print list(chain.from_iterable(zip(server1, server2, server3))) # [1, 3, 4, 2, 4, 5]
yield
也可以用在这里:
def f():
server1 = [1, 2]
server2 = [3, 4]
server3 = [4, 5]
for a, b, c in zip(server1, server2, server3):
yield a
yield b
yield c
val = f()
print [val.next() for _ in range(6)] # [1, 3, 4, 2, 4, 5]
我有一个服务器列表。每个服务器上都有一个名称列表。 示例:
server1 = ['a','b','c']
server2 = ['d','e','f']
server3 = ['g','h','i']
我想迭代每个服务器名称而不是每个服务器。例如在 server1
中选择 'a'
后,移动到 'd'
(而不是 'b'
)等等。如果我要使用 itertools.cycle()
,我是否必须创建一个服务器列表来循环?我的预期结果是 ['a','d','g','b','e','h','c','f','i']
。你能给我一个关于如何在多个列表中循环的简单例子吗?
试试这个:
from itertools import cycle
for k in cycle([j for i in zip(server1,server2,server3) for j in i]):
print(k)
#do you operations
a
d
g
b
...
但是关心这提供了无限循环
所以最好这样做:
c = cycle([j for i in zip(server1,server2,server3) for j in i])
>>>next(c)
a
>>>next(c)
b
....
您可以使用 zip
and reduce
内置函数(在 python3 functools.reduce
中):
>>> list_of_servers=[server1,server2,server3]
>>> s=reduce(lambda x,y:x+y,zip(*list_of_servers))
>>> s
('a', 'd', 'g', 'b', 'e', 'h', 'c', 'f', 'i')
或者对于长列表,您可以使用 itertools.chain
代替 reduce()
来连接 return 生成器的子列表:
>>> list(chain(*zip(*[server1,server2,server3])))
['a', 'd', 'g', 'b', 'e', 'h', 'c', 'f', 'i']
注意如果你想迭代你的结果,你不必在chain
的结果上使用list
。你可以做类似的事情:
for element in chain(*zip(*[server1,server2,server3])):
#do stuff
前面食谱的基准测试:
#reduce()
:~$ python -m timeit "server1 = ['a','b','c'];server2 = ['d','e','f'];server3 = ['g','h','i'];reduce(lambda x,y:x+y,zip(*[server1,server2,server3]))"
1000000 loops, best of 3: 1.11 usec per loop
#itertools.chain()
:~$ python -m timeit "server1 = ['a','b','c'];server2 = ['d','e','f'];server3 = ['g','h','i'];from itertools import chain;chain(*zip(*[server1,server2,server3]))"
100000 loops, best of 3: 2.02 usec per loop
请注意,如果您不将服务器放在列表中,速度会更快:
:~$ python -m timeit "server1 = ['a','b','c'];server2 = ['d','e','f'];server3 = ['g','h','i'];reduce(lambda x,y:x+y,zip(server1,server2,server3))"
1000000 loops, best of 3: 0.98 usec per loop
这个工作正常:
>>> from itertools import chain, islice, izip, cycle
>>> list(islice(cycle(chain.from_iterable(izip(server1, server2, server3))), 0, 18))
['a', 'd', 'g', 'b', 'e', 'h', 'c', 'f', 'i', 'a', 'd', 'g', 'b', 'e', 'h', 'c', 'f', 'i']
请注意,list
和 islice
仅用于演示目的,以显示内容并防止无限输出...
现在,如果你有不等长的列表,它会变得更有趣。然后 izip_longest
将成为您的朋友,但此时可能值得一个功能:
import itertools
def cycle_through_servers(*server_lists):
zipped = itertools.izip_longest(*server_lists, fillvalue=None)
chained = itertools.chain.from_iterable(zipped)
return itertools.cycle(s for s in chained if s is not None)
演示:
>>> from itertools import islice
>>> server3 = ['g', 'h', 'i', 'j']
>>> list(islice(cycle_through_servers(server1, server2, server3), 0, 20))
['a', 'd', 'g', 'b', 'e', 'h', 'c', 'f', 'i', 'j', 'a', 'd', 'g', 'b', 'e', 'h', 'c', 'f', 'i', 'j']
我们也可以使用 itertools.chain.from_iterable()
比较快。
import itertools
server1 = ['a','b','c']
server2 = ['d','e','f']
server3 = ['g','h','i']
print list(itertools.chain.from_iterable(zip(server1,server2,server3)))
结果:
['a', 'd', 'g', 'b', 'e', 'h', 'c', 'f', 'i']
from itertools import chain
for s in chain(*zip(server1, server2, server3)):
# do work
您可以使用链:
import itertools
server1 = ['a','b','c']
server2 = ['d','e','f']
server3 = ['g','h','i']
all_servers = [server1, server2, server3]
out_list = [s_name for a in itertools.chain(zip(*all_servers)) for s_name in a]
print(out_list)
#['a', 'd', 'g', 'b', 'e', 'h', 'c', 'f', 'i']
或更短:
out_list = list(itertools.chain.from_iterable(zip(*all_servers)))
standard library documentation 在 itertools
中将此功能作为配方提供。
def roundrobin(*iterables):
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
# Recipe credited to George Sakkis
pending = len(iterables)
nexts = cycle(iter(it).next for it in iterables)
while pending:
try:
for next in nexts:
yield next()
except StopIteration:
pending -= 1
nexts = cycle(islice(nexts, pending))
即使迭代器的长度不均匀,此代码也能正常工作,当较短的迭代器用完时循环遍历剩余的迭代器。这可能与您的用例相关,也可能不相关。
使用 chain
你可以简单地这样做:
from itertools import chain, izip
server1 = [1, 2]
server2 = [3, 4]
server3 = [4, 5]
print list(chain(*izip(server1, server2, server3))) # [1, 3, 4, 2, 4, 5]
或者您可以使用 chain.from_iterable
,它需要一个本身生成迭代器的可迭代对象。
在你的情况下 zip
是可迭代的,它以元组的形式生成迭代器:
print list(chain.from_iterable(zip(server1, server2, server3))) # [1, 3, 4, 2, 4, 5]
yield
也可以用在这里:
def f():
server1 = [1, 2]
server2 = [3, 4]
server3 = [4, 5]
for a, b, c in zip(server1, server2, server3):
yield a
yield b
yield c
val = f()
print [val.next() for _ in range(6)] # [1, 3, 4, 2, 4, 5]