Vadim Yanko Vadim Yanko - 2 months ago 13
Python Question

Reverse the list while creation

I have this code:

def iterate_through_list_1(arr):
lala = None
for i in range(len(arr))[::-1]:
lala = i

def iterate_through_list_2(arr):
lala = None
for i in range(len(arr), 0, -1):
lala = i


Logically, iterating through list created by
range()
in reverse order should be more efficient, than creating list with
range()
and reversing it afterwards with
[::-1]
. But cProfile tells me, that
iterate_through_list_1
function works faster.

I used python-3. And here you can see output of profiling on the two identical arrays with 100000000 elements in them.

ncalls tottime percall cumtime percall filename:lineno(function)
1 5.029 5.029 5.029 5.029 bs.py:24(iterate_throgh_list_2)
1 4.842 4.842 4.842 4.842 bs.py:19(iterate_throgh_list_1)


What happened underneath Python slices while list creation?

Answer

Well designed test shows that first function is slowest on Python 2.x (mostly because two lists have to be created, first one as a increasing range, second one as a reverted first one). I also included a demo using reversed.

from __future__ import print_function
import sys
import timeit

def iterate_through_list_1(arr):
    lala = None
    for i in range(len(arr))[::-1]:
        lala = i

def iterate_through_list_2(arr):
    lala = None
    for i in range(len(arr), 0, -1):
        lala = i

def correct_iterate_reversed(arr):
    lala = None
    for obj in reversed(arr):
        lala = obj


print(sys.version)
print('iterate_through_list_1', timeit.timeit('iterate_through_list_1(seq)',
                                              setup='from __main__ import iterate_through_list_1\nseq = range(0, 10000)',
                                              number=10000))
print('iterate_through_list_2', timeit.timeit('iterate_through_list_2(seq)',
                                              setup='from __main__ import iterate_through_list_2\nseq = range(0, 10000)',
                                              number=10000))
print('correct_iterate_reversed', timeit.timeit('correct_iterate_reversed(seq)',
                                                setup='from __main__ import correct_iterate_reversed\nseq = range(0, 10000)',
                                                number=10000))

Results:

2.7.12 (default, Jun 29 2016, 14:05:02) 
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)]
iterate_through_list_1 3.87919592857
iterate_through_list_2 3.38339591026
correct_iterate_reversed 2.78083491325

Differences in 3.x are all neglible, because in each case objects iterated over are lazy.

3.5.2 (default, Jul 28 2016, 21:28:00) 
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)]
iterate_through_list_1 2.986786328998278
iterate_through_list_2 2.9836046030031866
correct_iterate_reversed 2.9411962590020266