创建重复N次的单项列表

我想创建一系列长度不同的列表。每个列表将包含相同的元素e,重复n次(其中n=列表的长度)。

如何创建列表,而不对每个列表使用列表理解[e for number in xrange(n)]

854237 次浏览

IterTools有一个函数就是为了这个:

import itertools
it = itertools.repeat(e,n)

当然,itertools给你一个迭代器而不是列表。[e] * n给你一个列表,但是,根据你将对这些序列做什么,itertools变体可以更有效。

你也可以写:

[e] * n

你应该注意,如果e是一个空列表,你会得到一个对同一个列表有n个引用的列表,而不是n个独立的空列表。

性能测试

乍一看,重复的似乎是创建具有n个相同元素的列表的最快方法:

>>> timeit.timeit('itertools.repeat(0, 10)', 'import itertools', number = 1000000)
0.37095273281943264
>>> timeit.timeit('[0] * 10', 'import itertools', number = 1000000)
0.5577236771712819

但是等等-这不是一个公平的测试…

>>> itertools.repeat(0, 10)
repeat(0, 10)  # Not a list!!!

函数itertools.repeat实际上并没有创建列表,它只是创建了一个对象,如果您愿意,可以使用该对象创建列表!让我们再试一次,但转换为列表:

>>> timeit.timeit('list(itertools.repeat(0, 10))', 'import itertools', number = 1000000)
1.7508119747063233

因此,如果您想要一个列表,请使用[e] * n。如果您想延迟生成元素,请使用repeat

>>> [5] * 4
[5, 5, 5, 5]

当重复的项目是列表时要小心。列表不会被克隆:所有元素都将引用同一个列表!

>>> x=[5]
>>> y=[x] * 4
>>> y
[[5], [5], [5], [5]]
>>> y[0][0] = 6
>>> y
[[6], [6], [6], [6]]
[e] * n

应该起作用

在Python中创建重复n次的单个项目列表

根据您的用例,您希望在不同的语义学中使用不同的技术。

为不可变项乘以列表

对于不可变的项目,如无、布尔、整数、浮点数、字符串、元组或Frozenset,您可以这样做:

[e] * 4

请注意,这通常仅用于列表中的不可变项(字符串、元组、Frozenset、),因为它们都指向内存中同一位置的同一项。当我必须使用所有字符串的模式构建表时,我经常使用它,这样我就不必给出高度冗余的一对一映射。

schema = ['string'] * len(columns)

将我们希望重复相同项目的列表相乘

将列表乘以一遍又一遍地为我们提供相同元素。很少需要这样做:

[iter(iterable)] * 4

这有时用于将可迭代映射到列表列表中:

>>> iterable = range(12)
>>> a_list = [iter(iterable)] * 4
>>> [[next(l) for l in a_list] for i in range(3)]
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]

我们可以看到a_list包含四次相同的范围迭代器:

>>> a_list
[<range_iterator object at 0x7fde73a5da20>, <range_iterator object at 0x7fde73a5da20>, <range_iterator object at 0x7fde73a5da20>, <range_iterator object at 0x7fde73a5da20>]

可变项目

我已经使用Python很长时间了,我很少看到用可变对象执行上述操作的用例。

相反,要获得,比如说,一个可变的空列表、集合或字典,你应该这样做:

list_of_lists = [[] for _ in columns]

下划线在这种情况下只是一个一次性变量名。

如果你只有数字,那就是:

list_of_lists = [[] for _ in range(4)]

_并不特别,但如果您不打算使用该变量并使用任何其他名称,您的编码环境样式检查器可能会抱怨。


将不可变方法与可变项一起使用的注意事项:

小心使用可变对象执行此操作,当你改变其中一个时,它们都会改变,因为它们都是相同对象:

foo = [[]] * 4
foo[0].append('x')

foo现在返回:

[['x'], ['x'], ['x'], ['x']]

但是对于不可变对象,你可以让它工作,因为你改变了引用,而不是对象:

>>> l = [0] * 4
>>> l[0] += 1
>>> l
[1, 0, 0, 0]


>>> l = [frozenset()] * 4
>>> l[0] |= set('abc')
>>> l
[frozenset(['a', 'c', 'b']), frozenset([]), frozenset([]), frozenset([])]

但同样,可变对象对此没有好处,因为就地操作改变的是对象,而不是引用:

l = [set()] * 4
>>> l[0] |= set('abc')
>>> l
[set(['a', 'c', 'b']), set(['a', 'c', 'b']), set(['a', 'c', 'b']), set(['a', 'c', 'b'])]

正如其他人所指出的,对可变对象使用*运算符会重复引用,因此如果你更改一个,你就会更改所有引用。如果你想创建可变对象的独立实例,你的xrange语法是最Pythonic的方法。如果你对有一个从未使用过的命名变量感到困扰,你可以使用匿名下划线变量。

[e for _ in xrange(n)]

如果你正在寻找一个简单的重复:

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

只需使用:

[1, 2, 3] * 3

如果您正在寻找:

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

这个更好,但需要更多时间:

numpy.concatenate([([i]*3) for i in [1,2,3]], axis=0)

很抱歉我的回答太迟了 您可以轻松使用numpy.repeat。只需写下您想要生成的值和重复次数。

import numpy as np
x = [1,2,3]
y = np.linspace(0,1000,10000)
for i in x:
new_x = np.repeat(i,len(y))
print(new_x)

如果你在寻找

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

如果没有numpy,您可以使用内置的迭代工具模块

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

使用一个简单的列表理解(甚至不需要迭代工具)

[e for x in zip(*[[1,2,3]]*3) for e in x]