簡體   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