Есть ли элегантный способ циклически перебирать список N раз через итерацию (например, itertools.cycle, но ограничивать циклы)?

Я хотел бы циклически перебирать список (N раз) через итератор, чтобы фактически не хранить N копий списка в памяти. Есть ли встроенный или элегантный способ сделать это без написания моего собственного генератора?

В идеале, itertools.cycle(my_list) будет иметь второй аргумент, чтобы ограничить, сколько раз он циклы... увы, нет такой удачи.

Ответ 1

import itertools
itertools.chain.from_iterable(itertools.repeat([1, 2, 3], 5))

Itertools - замечательная библиотека.:)

Ответ 2

itertools.chain.from_iterable(iter(L) for x in range(N))

Ответ 3

Для частного случая, когда вам нужно несколько раз перебирать список, это не так уж плохо.

Он создает список n ссылок на my_list, поэтому, если n очень велико, лучше использовать ответ Дартфелта

>>> import itertools as it
>>> it.chain(*[my_list]*n)

Ответ 4

Все остальные ответы превосходны. Другим решением было бы использовать islice. Это позволяет прерывать цикл в любой момент:

>>> from itertools import islice, cycle
>>> l = [1, 2, 3]
>>> list(islice(cycle(l), len(l) * 3))
[1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> list(islice(cycle(l), 7))
[1, 2, 3, 1, 2, 3, 1]

Ответ 5

Вы сказали, что не хотите писать свой собственный генератор, но выражение генератора, вероятно, будет самым простым и эффективным способом выполнить то, что вам нужно. Он не требует каких-либо вызовов функций или импорта каких-либо модулей. itertools - отличный модуль, но, возможно, не нужен в этом случае?

some_list = [1, 2, 3]
cycles = 3
gen_expr = (elem for _ in xrange(cycles) for elem in some_list)

или просто

(elem for _ in xrange(3) for elem in [1, 2, 3])

или

for elem in (e for _ in xrange(3) for e in [1, 2, 3]):
    print "hoo-ray, {}!".format(elem)

Ответ 6

@Ответ Darthfett задокументирован как рецепты itertools:

from itertools import chain, repeat

def ncycles(iterable, n):
    "Returns the sequence elements n times"
    return chain.from_iterable(repeat(tuple(iterable), n))


list(ncycles(["a", "b"], 3))
# ['a', 'b', 'a', 'b', 'a', 'b']

Для удобства добавлю, что библиотека more_itertools реализует этот рецепт (и многие другие) для вас:

import more_itertools as mit

list(mit.ncycles(["a", "b"], 3))
# ['a', 'b', 'a', 'b', 'a', 'b']