繁体   English   中英

在 python 中创建列表的最佳和/或最快的方法

[英]Best and/or fastest way to create lists in python

在 python 中,据我所知,至少有 3 到 4 种方法来创建和初始化给定大小的列表:

带有append简单循环:

my_list = []
for i in range(50):
    my_list.append(0)

+=简单循环:

my_list = []
for i in range(50):
    my_list += [0]

列表理解:

my_list = [0 for i in range(50)]

列表和整数乘法:

my_list = [0] * 50

在这些示例中,鉴于列表只有 50 个元素,我认为不会有任何性能差异,但是如果我需要一百万个元素的列表怎么办? 使用xrange会有所改善吗? 在 python 中创建和初始化列表的首选/最快方法是什么?

让我们用timeit.timeit运行一些时间测试*:

>>> from timeit import timeit
>>>
>>> # Test 1
>>> test = """
... my_list = []
... for i in xrange(50):
...     my_list.append(0)
... """
>>> timeit(test)
22.384258893239178
>>>
>>> # Test 2
>>> test = """
... my_list = []
... for i in xrange(50):
...     my_list += [0]
... """
>>> timeit(test)
34.494779364416445
>>>
>>> # Test 3
>>> test = "my_list = [0 for i in xrange(50)]"
>>> timeit(test)
9.490926919482774
>>>
>>> # Test 4
>>> test = "my_list = [0] * 50"
>>> timeit(test)
1.5340533503559755
>>>

正如你在上面看到的,最后一种方法是迄今为止最快的。


但是,它应该用于不可变项(例如整数)。 这是因为它将创建一个引用相同项目的列表。

下面是一个演示:

>>> lst = [[]] * 3
>>> lst
[[], [], []]
>>> # The ids of the items in `lst` are the same
>>> id(lst[0])
28734408
>>> id(lst[1])
28734408
>>> id(lst[2])
28734408
>>>

这种行为通常是不可取的,并可能导致代码中的错误。

如果您有可变项目(例如列表),那么您应该使用仍然非常快的列表推导式:

>>> lst = [[] for _ in xrange(3)]
>>> lst
[[], [], []]
>>> # The ids of the items in `lst` are different
>>> id(lst[0])
28796688
>>> id(lst[1])
28796648
>>> id(lst[2])
28736168
>>>

*注意:在所有测试中,我都用xrange替换了range 由于后者返回一个迭代器,它应该总是比前者快。

如果要查看列表长度为n的依赖项:

纯蟒蛇

在此处输入图片说明

我测试了最多 n=10000 的列表长度,并且行为保持不变。 所以整数乘法是最快的有差异的。

麻木

对于包含超过 300 个元素的列表,您应该考虑numpy

在此处输入图片说明

基准代码:

import time

def timeit(f):

    def timed(*args, **kwargs):
        start = time.clock()
        for _ in range(100):
            f(*args, **kwargs)
        end = time.clock()
        return end - start
    return timed

@timeit
def append_loop(n):
    """Simple loop with append"""
    my_list = []
    for i in xrange(n):
        my_list.append(0)

@timeit
def add_loop(n):
    """Simple loop with +="""
    my_list = []
    for i in xrange(n):
        my_list += [0]

@timeit   
def list_comprehension(n):        
    """List comprehension"""
    my_list = [0 for i in xrange(n)]

@timeit
def integer_multiplication(n):
    """List and integer multiplication"""
    my_list = [0] * n


import numpy as np

@timeit
def numpy_array(n):
    my_list = np.zeros(n)
    

import pandas as pd 

df = pd.DataFrame([(integer_multiplication(n), numpy_array(n)) for n in range(1000)], 
                  columns=['Integer multiplication', 'Numpy array'])
df.plot()

要点在这里

还有一种方法,虽然听起来很奇怪,但在正确的姜黄中很方便。 如果您需要多次生成相同的列表(在我的情况下为roguelike 寻路和相关内容初始化矩阵),您可以将列表的副本存储在元组中,然后在需要时将其转换为列表。 它明显比通过推导式生成列表快,并且与列表乘法不同,它适用于嵌套数据结构。

#  In class definition
def __init__(self):
    self.l = [[1000 for x in range(1000)] for y in range(1000)]
    self.t = tuple(self.l)

def some_method(self):
    self.l = list(self.t)
    self._do_fancy_computation()
    #  self.l is changed by this method

#  Later in code:
for a in range(10):
    obj.some_method()

瞧,在每次迭代中,您都会立即获得相同列表的新副本!

免责声明:

我不知道为什么这么快,或者它是否可以在 CPython 3.4 之外的任何地方工作。

如果要创建一个递增的列表,即每次加 1,请使用range函数。 range中包含 start 参数并排除 end 参数,如下所示:

list(range(10,20))
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

如果您想通过向前面的元素添加 2 来创建列表,请使用以下命令:

list(range(10,20,2))
[10, 12, 14, 16, 18]

这里的第三个参数是要采用的步长。 现在,您可以提供任何开始元素、结束元素和步长,并快速轻松地创建许多列表。

谢谢..!

快乐学习.. :)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM