使用itertools.cycle()循环遍历多个列表

uni*_*ice 13 python python-itertools

我有一个服务器列表.每个服务器上都有一个名称列表.例:

server1 = ['a','b','c']
server2 = ['d','e','f']
server3 = ['g','h','i']
Run Code Online (Sandbox Code Playgroud)

我想迭代每个服务器名称而不是每个服务器.例如,在选择'a'之后server1,移动到'd'(不'b')等等.如果我要使用itertools.cycle(),我是否必须创建一个服务器列表来循环?我的预期结果是['a','d','g','b','e','h','c','f','i'].你能给我一个关于如何在多个列表中循环的简单示例.

Tan*_*lam 11

我们也可以使用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)))
Run Code Online (Sandbox Code Playgroud)

结果:

['a', 'd', 'g', 'b', 'e', 'h', 'c', 'f', 'i']
Run Code Online (Sandbox Code Playgroud)


Kas*_*mvd 9

你可以使用with zipreduce内置函数(以及在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')
Run Code Online (Sandbox Code Playgroud)

或者代替reduce()长列表,您可以使用itertools.chain连接返回生成器的子列表:

>>> list(chain(*zip(*[server1,server2,server3])))
['a', 'd', 'g', 'b', 'e', 'h', 'c', 'f', 'i']
Run Code Online (Sandbox Code Playgroud)

请注意,如果要迭代结果,则不必使用list结果chain.你可以这样做:

for element in chain(*zip(*[server1,server2,server3])):
     #do stuff
Run Code Online (Sandbox Code Playgroud)

对前面的食谱进行基准测试:

#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
Run Code Online (Sandbox Code Playgroud)

请注意,如果您不将服务器放在列表中,它会更快:

:~$ 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
Run Code Online (Sandbox Code Playgroud)

  • @Kasra,reduce只会看起来更快,因为你在计算中包含了导入链所需的时间.使用来自itertools导入链的"python -mtimeit -s"""server1 = ['a','b','c']; server2 = ['d','e','f']; server3 = [' g','h','i'];链(*zip(server1,server2,server3));"`将导入移出定时块给我0.889 usec for chain,而你的reduce版本需要1.24 usec on我的机器 (3认同)

mgi*_*son 7

这个工作正常:

>>> 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']
Run Code Online (Sandbox Code Playgroud)

注意,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)
Run Code Online (Sandbox Code Playgroud)

演示:

>>> 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']
Run Code Online (Sandbox Code Playgroud)


Pau*_*kin 5

标准库文档提供了这个功能作为一个配方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))
Run Code Online (Sandbox Code Playgroud)

即使可迭代的长度不均匀,当较短的长度用完时循环通过剩余的代码,此代码也可以工作.这可能与您的用例有关,也可能与您的用例无关.