2012-04-26 50 views
11

我想通过一个迭代器反复遍历一个列表(N次),以免在列表中实际存储N个列表副本。有没有内置或优雅的方式来做到这一点,而不写我自己的发电机?是否有一种优雅的方式通过迭代遍历列表N次(如itertools.cycle但限制循环)?

理想情况下,itertools.cycle(my_list)将有第二个参数来限制它循环的次数...唉,没有这样的运气。

+0

我相信乘以一个整数列表是不够好,对吗? '[1,2,3] * 4' – C2H5OH 2012-04-26 00:06:42

+0

@ C2H5OH这将创建列表的4个浅拷贝(N个拷贝是不需要的)。 – Darthfett 2012-04-26 00:17:52

+0

@Darthfett:确实。这就是为什么它是一个评论。但是你会同意这是最优雅的解决方案:-P – C2H5OH 2012-04-26 00:19:22

回答

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

Itertools是一个奇妙的图书馆。 :)

+0

这是一个相当明确的答案,不涉及我自己的生成器/迭代器(尽管马特安德森的回答显示这不是太混乱),并且是一个满足我的问题的第一个答案。所以,我接受它。谢谢!! – JJC 2012-04-26 08:57:02

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

对于需要多次迭代列表的特殊情况,这并不算太坏。

它确实创造n引用列表来my_list,所以如果n是非常大的,最好是用Darthfelt的回答

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

我试图避免在内存中复制列表(或引用它),否则只是:mylist * n将会是足够的。 :-)尽管如此,感谢您的意见。只需要清楚,通过* list运算符扩展列表并将其乘以n而不是将列表乘以n?是否有区别? – JJC 2012-04-26 13:34:52

+0

@JJC,'mylist * n'用'len(mylist)* n)'元素创建一个列表。对于这个答案,你只需创建一个'n'元素列表,所以根据'len(mylist)'和'n',这可能会产生巨大的差异 – 2012-04-26 22:08:05

+0

我明白[1,2,3,4] * 2会创建一个8个元素的列表。那么,你说* [1,2,3,4] * 2只创建了两个元素?对不起,我很困惑。谢谢。 – JJC 2012-04-28 09:36:19

5

其他所有的答案都非常优秀。另一种解决方案是使用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] 
+0

不错,我不知道islice处理大于可迭代长度的“stop”值。 – Darthfett 2012-04-26 00:33:21

+1

@Darthfett,是的,它的确如此。但这在这里不重要。由'cycle'返回的iterable无限长。 – senderle 2012-04-26 00:35:15

3

你说你不想写自己的发电机,但发电机表达式很可能会完成你”最简单,最有效的方法重新过后。它不需要任何函数调用或任何模块的导入。 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) 
+0

我喜欢这些生成器表达式。它们比我意识到它们适合这种模式更紧凑。我将答案归功于@Darthfett,因为技术上我要求一个非自动滚动的发电机,但是如果我可以接受两个发电机,我也会接受你的(也可能是别人的:-))谢谢! – JJC 2012-04-26 08:52:50

1

@ Darthfett的答案被记录为一个itertools recipes

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'] 
+0

谢谢,但这与Darthfett接受的答案相同。 – JJC 2017-08-23 13:08:51

+0

是的,它们是等价的。我编辑澄清他的代码是现有的'itertools'配方(不早于Python 2.3)。我发布此选项来演示实现这些配方的第三方库,并在需要时避免手动实施。谢谢。 – pylang 2017-08-23 15:46:29

+1

很酷。 more_itertools包看起来非常方便。感谢分享它。 – JJC 2017-08-24 14:23:59