在Python中,遍历列表的最有效方法是什么?

35

假设我有一个项目列表:

x = [1, 2, 3, 4, 5]

我需要对这些项执行一些函数。在某些情况下,我需要返回一个项的索引。

哪种方法最好且最有效?

for item in list:
    ....
或者。
for i in range(len(list)):
    ....

3
请在发帖前搜索论坛。这个问题已经被回答了许多次。 - sulabh
@sulabh:我找不到这个问题的确切副本。请提供链接。我在这里提出的问题是关于两种不同的迭代列表方式的比较,并建议哪种更好。 - mankand007
2
如果这不是完全重复的话,能否请人们撤回他们的踩?我很穷,你知道的... - mankand007
我要警告可能产生的误解,即列表是高效的容器。它们并不是。如果您计划迭代大型数据集,则列表不高效。请参见下面的示例,应该使用numpy数组,它们不太灵活,但可以处理大小。 - DISC-O
4个回答

29
for item in list:

显然,这个带有较少函数调用的方法是更好的选择。

如果您想在操作过程中获取项的索引,请使用enumerate,像这样:

for pos, item in enumerate(collection):

28
def loop_1(data):
    for i in range(len(data)):
        print(data[i])


def looper_2(data):
    for val in data:
        print(val)

使用dis检查loop_1的字节码,得到以下结果:

 12       0 SETUP_LOOP              40 (to 43)
          3 LOAD_GLOBAL              0 (range)
          6 LOAD_GLOBAL              1 (len)
          9 LOAD_FAST                0 (data)
         12 CALL_FUNCTION            1
         15 CALL_FUNCTION            1
         18 GET_ITER            
    >>   19 FOR_ITER                20 (to 42)
         22 STORE_FAST               1 (i)

13       25 LOAD_GLOBAL              2 (print)
         28 LOAD_FAST                0 (data)
         31 LOAD_FAST                1 (i)
         34 BINARY_SUBSCR       
         35 CALL_FUNCTION            1
         38 POP_TOP             
         39 JUMP_ABSOLUTE           19
    >>   42 POP_BLOCK           
    >>   43 LOAD_CONST               0 (None)
         46 RETURN_VALUE        

loop_2 的字节码如下:

17        0 SETUP_LOOP              24 (to 27)
          3 LOAD_FAST                0 (data)
          6 GET_ITER            
    >>    7 FOR_ITER                16 (to 26)
         10 STORE_FAST               1 (val)

18       13 LOAD_GLOBAL              0 (print)
         16 LOAD_FAST                1 (val)
         19 CALL_FUNCTION            1
         22 POP_TOP             
         23 JUMP_ABSOLUTE            7
    >>   26 POP_BLOCK           
    >>   27 LOAD_CONST               0 (None)
         30 RETURN_VALUE

第二个版本明显更好。


5
显然,for i in range(len(list)): 会更慢 - 在Python 2中,它等效于以下代码:
list2 = range(len(list))

for i in list2:
    ...

如果那个更快,那么这个就会更快,对吗?
list2 = range(len(list))
list3 = range(len(list2))
list4 = range(len(list3))

for i in list4:
    ...

5

另一个可能的解决方案是使用 numpy,对于大型列表来说,它非常高效,甚至比列表推导式或for循环更高效。

import numpy as np

a = np.arange(5.0)   # a --> array([0., 1., 2., 3., 4.])

# numpy operates on arrays element by element 
#
b =3.*a              # b --> array([0., 3., 6., 9., 12.])

这是一个相当简单的操作,但是你可以使用数组作为公式中的参数来使其更加复杂。对于大型数组,这比列表推导要快得多,而且使代码更清晰易读(无需创建映射函数)。您还可以使用索引和切片来定制您想要做的事情:
如果您想访问实际的索引位置,请使用ndenumerate。
# b is as above
for i, x in np.ndenumerate(b):
    print i, x

这个for循环的输出结果是:
(0,) 0.0 
(1,) 3.0 
(2,) 6.0 
(3,) 9.0 
(4,) 12.0 

注意:numpy返回的索引是元组,用于处理额外的维度。在这里我们只有一个维度,因此您需要解包元组以获取元素的索引。


1
你能添加一些关于这个的细节吗? - Hotloo Xiranood

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