如何使用itertools仅重复Python列表的每个元素n次?

11

我有一个数字列表:

numbers = [1, 2, 3, 4]

我想要生成一个重复 n 次的列表,例如(对于n = 3):

[1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]

问题在于,我只想使用 itertools 来完成这个任务,因为我非常注重性能。

我尝试使用以下表达式:

list(itertools.chain.from_iterable(itertools.repeat(numbers, 3)))

但它给出了我这样的结果:

[1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]

这显然不是我需要的。

是否有一种仅使用 itertools 完成此操作的方法,而不使用排序、循环和列表理解?我最接近的结果是:

list(itertools.chain.from_iterable([itertools.repeat(i, 3) for i in numbers]))

但它也使用了列表理解,我希望避免使用。


你有避免使用列表推导式的原因吗?它们非常快,通常与 itertools 一样高效。 - pylang
同样的问题,但没有对itertools的限制:将列表中的元素重复n次 - Georgy
3个回答

13

首先,使用来自itertools 的函数并不一定比使用列表推导更快:您应该进行基准测试。

纯列表推导方法:

首先,使用来自itertools的函数并不一定比使用列表推导更快: 您应该执行基准测试.

纯列表推导方法:

>>> numbers = [1, 2, 3, 4]
>>> [y for x in numbers for y in (x,)*3]
[1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]

在生成器表达式中使用chain.from_iterable()repeat()

>>> from itertools import chain, repeat
>>> list(chain.from_iterable(repeat(n, 3) for n in numbers))
[1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]

使用chain.from_iterable()zip()

>>> from itertools import chain
>>> list(chain.from_iterable(zip(*(numbers,)*3)))
[1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]

1
我发现这个列表推导式更容易理解,并且对于更大的重复值来说速度更快:[x for x in numbers for _ in range(3)]。我怀疑乘法方法的较低迭代边缘是由于 range 函数调用开销造成的。 - Mattwmaster58
@Mattwmaster58:你可以用repeat(None, 3)替换range(3)来稍微提高一点速度,但仍然是乘法版本更快。 - Eugene Yarmash

6

如果您不想使用列表推导式,以下是一个纯粹的(+zipitertools方法来实现 -

from itertools import chain, repeat

list(chain.from_iterable(zip(*repeat(numbers, 3))))
# [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]

3

我认为你很接近了,只需要将推导式改写成生成器:

n = 3
numbers = [1, 2, 3, 4]
list(itertools.chain.from_iterable((itertools.repeat(i, n) for i in numbers)))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接