Каков наиболее эффективный способ перебора списка в python?

Скажем, у меня есть список элементов:

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

Мне нужно выполнить некоторые функции для каждого из этих элементов. В определенном случае мне нужно вернуть индекс элемента.

Каков наилучший и эффективный способ?

for item in list:
    ....

или

for i in range(len(list)):
    ....

Ответ 1

for item in list:

это, очевидно, тот, с меньшим количеством вызовов функций.

Если вы хотите получить индекс предметов по ходу дела, используйте перечисление, как это

for pos, item in enumerate(collection):

Ответ 2

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

Вторая версия, очевидно, лучше.

Ответ 3

Другим возможным решением было бы использовать 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 для обработки дополнительных измерений. Здесь мы имеем только одно измерение, поэтому вам нужно будет распаковать кортеж, чтобы получить индекс элемента.

Ответ 4

Очевидно, что 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:
    ...