如何将Python列表的所有值设置为特定值?

2024-06-06 14:00:57 发布

您现在位置:Python中文网/ 问答频道 /正文

是否可以将Python列表中的所有值设置为0,而不逐个迭代列表和值?在

我有一个列表列表[[0, 2, 4, 5], [0, 2, 4, 5]],我想将其改为[[0, 0, 0, 0], [0, 0, 0, 0]]。有没有一种方法可以在不遍历所有值的情况下实现这一点?这会导致性能改进吗?既然这段代码将被执行大量次,那么实现这一点的最快方法是什么?在

这些清单是就地修改还是全部替换也无关紧要。外部列表的长度将相当大,而内部列表的长度将很小。在


Tags: 方法代码列表情况性能
3条回答

在没有显式循环的情况下,下面是一个使用itertools.repeat()map()的函数方法:

In [6]: lst = list(map(lambda x: list(repeat(0, len(x))), lst))
Out[6]: [[0, 0, 0, 0], [0, 0, 0, 0]]

或者,如果您的子列表长度相同,您可以使用两个repeat()

^{pr2}$

注意,这些方法使用循环来创建重复对象并将生成器转换为列表。这意味着如果没有循环,就无法创建这样的单独对象。在

另一种更改项目的方法是使用Numpy。只需将0乘以即可:

In [18]: import numpy as np

In [19]: lst = np.array(lst)

In [21]: lst *= 0

In [22]: lst
Out[22]: 
array([[0, 0, 0, 0],
       [0, 0, 0, 0]])

不,没有办法避免循环,因为列表的大小是任意的。您还希望避免以共享的单个嵌套列表结尾,这样外部列表的乘法运算就结束了。在

以下是合理有效的,并产生合理的结果:

[[0] * len(inner) for inner in outer]

这将为任何长度的outer生成正确的结果,即使嵌套列表的长度不同。在

这也是在不同情况下最快的方法,如下时间试验所示。首先要测试的设置:

^{pr2}$

我在python3.6.1rc1上用^{} module在运行OSX10.12.3的MacBookPro(Retina,15英寸,2015年年中)上进行测试

然后是每个场景。Short fixed是一个由10个嵌套列表组成的列表,每个列表的长度为5个元素。测试时间为100万次重复的总次数:

>>> timeit('list(map(lambda x:[0]*len(x),l))', 'from __main__ import short_fixed as l')
3.2795075319882017
>>> timeit('list(map(lambda x: list(repeat(0, len(x))), l))', 'from __main__ import short_fixed as l; from itertools import repeat')
6.128518687008182
>>> timeit('[[0] * len(inner) for inner in l]', 'from __main__ import short_fixed as l')
2.254983870021533

长时间固定测试100万个元素,重复10次以保持等待可控:

>>> timeit('list(map(lambda x:[0]*len(x),l))', 'from __main__ import long_fixed as l', number=10)
3.955955935991369
>>> timeit('list(map(lambda x: list(repeat(0, len(x))), l))', 'from __main__ import long_fixed as l; from itertools import repeat', number=10)
6.772360901988577
>>> timeit('[[0] * len(inner) for inner in l]', 'from __main__ import long_fixed as l', number=10)
3.302304288983578

不同的列表大小在0到25个元素之间。短名单:

>>> timeit('list(map(lambda x:[0]*len(x),l))', 'from __main__ import short_ranging as l')
3.155180420988472
>>> timeit('list(map(lambda x: list(repeat(0, len(x))), l))', 'from __main__ import short_ranging as l; from itertools import repeat')
6.213294043001952
>>> timeit('[[0] * len(inner) for inner in l]', 'from __main__ import short_ranging as l')
2.3255828430119436

最后还有100万个测距表:

>>> timeit('list(map(lambda x: list(repeat(0, len(x))), l))', 'from __main__ import long_ranging as l; from itertools import repeat', number=10)
8.005676712986315
>>> timeit('list(map(lambda x: list(repeat(0, len(l[0]))), l))', 'from __main__ import long_ranging as l; from itertools import repeat', number=10)
8.49916388199199
>>> timeit('[[0] * len(inner) for inner in l]', 'from __main__ import long_ranging as l', number=10)
3.8087494230130687

在所有场景中,显式循环的速度都比lambda快(高达2倍),因为它不必使用lambda函数。在

如果您准备切换到numpy数组,那么这个选项可以很容易地将所有内容都从水中清除掉。在数组中的所有(本机)值上广播0的乘法将所有迭代移动到C,而不需要调用函数或执行Python字节码:

>>> import numpy
>>> short_fixed_np = numpy.array(short_fixed)
>>> long_fixed_np = numpy.array(long_fixed)
>>> short_ranging_np = numpy.array(short_ranging)
>>> long_ranging_np = numpy.array(long_ranging)
>>> timeit('l = next(copies); l *= 0', 'from __main__ import short_fixed_np as arr, numpy; copies = iter([numpy.copy(arr) for _ in range(10**6)])')
0.8011195910221431
>>> timeit('l = next(copies); l *= 0', 'from __main__ import long_fixed_np as arr, numpy; copies = iter([numpy.copy(arr) for _ in range(10)])', number=10)
0.04912398199667223

(因为这种方法在适当的地方改变了对象,所以您需要为每个单独的重复测试创建足够的副本来改变一个唯一的数组,因此整个next(copies)舞蹈)。在

充分使用numpy数组还意味着您只能实际地将它们用于固定长度的子列表。对于可变长度的子列表,您必须使用object类型的一维数组(这意味着它们仅用于引用Python列表),此时您也不能再将乘法广播到所有数值元素。在

考虑到在这种情况下,为了利用numpy数组,您必须重新组合整个项目。如果您需要从这样一个数组中多次访问单个值,那么请考虑这样做会比较慢,因为每次访问单个值都需要在Python对象中装箱C本机值。在

据我所知,避免循环是不可能的,但是你说过显式循环,我想你想要一种没有for循环的方法。在

所以你可以试试这个:

print map(lambda x:[0]*len(x),l)

Python 3.x,它应该是:

^{pr2}$

Map

Apply function to every item of iterable and return a list of the results.

相关问题 更多 >