iterating in reverse

Chad Netzer cnetzer at mail.arc.nasa.gov
Thu Jan 16 22:02:56 EST 2003


On Thursday 16 January 2003 17:30, Carl Banks wrote:
> Chad Netzer wrote:
> > FWIW. list.reverse() is often not too bad since it only has to do
> > the work of reversing the list indices in memory, not copying the
> > actual objects themselves.  Iterating backwards does save an O(N)
> > operation, but for small lists, list.reverse() is likely faster.
>
> Iterating a list is an O(N) operation itself.  If .reverse() is
> faster for a small list, it should also be faster for a large list.

Well, true of course.  I was thinking there might be possible cache 
poisoning effects that would occur for large lists (since a 
copy/reverse/iteration implies three linear passes though the indices, 
versus 1 for reverse_iter()). 

> The only problem with .reverse() is you might want to keep the
> unreversed list around.

Yeah, so you may need to do a copy/reverse  or a reverse/reverse, to 
keep the original list.

I wrote a quick, crude benchmark, and it seems that list.reverse() is 
always a speed win over reverse_iter.  It would be interesting to 
compare the other methods suggested in this thread.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from __future__ import generators
from __future__ import division

import time

def reverse_iter( seq ):
    i = 0
    n = len( seq )
    while i < n:
        j = -(i + 1)
        yield seq[ j ]
        i += 1

if __name__ == '__main__':
    N = 100

    seq = range(1,10,2)
    seq += range( 10, 100, 20 )
    seq += range( 100, 1000, 200 )
    seq += range( 1000, 10000, 2000 )
    seq += range( 10000, 100000, 20000 )

    print "t1: avg time for list reversal, t2: avg time for reverse 
iterator"
    for list_len in seq:
        l = [None] * list_len

        start_time = time.time()
        for i in range( N ):
            g = l[:]
            g.reverse()
            for j in g:
                pass
        end_time = time.time()
        reverse_list_time = (end_time - start_time) / N

        start_time = time.time()
        for i in range( N ):
            for j in reverse_iter( l ):
                pass
        end_time = time.time()
        reverse_iter_time = (end_time - start_time) / N
        ratio = reverse_iter_time / reverse_list_time

        s = "list len %7d: t1 %f,\tt2 %f,\tratio %f"
        print s %(list_len, reverse_list_time, reverse_iter_time, ratio)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
$ python reverse_iter_test.py
t1: avg time for list reversal, t2: avg time for reverse iterator
list len       1: t1 0.000007,	t2 0.000009,	ratio 1.368592
list len       3: t1 0.000008,	t2 0.000014,	ratio 1.787987
list len       5: t1 0.000009,	t2 0.000019,	ratio 2.232744
list len       7: t1 0.000010,	t2 0.000046,	ratio 4.472117
list len       9: t1 0.000145,	t2 0.000029,	ratio 0.199969
list len      10: t1 0.000011,	t2 0.000032,	ratio 2.855135
list len      30: t1 0.000022,	t2 0.000080,	ratio 3.729080
list len      50: t1 0.000030,	t2 0.000130,	ratio 4.276323
list len      70: t1 0.000040,	t2 0.000180,	ratio 4.500167
list len      90: t1 0.000049,	t2 0.000230,	ratio 4.727376
list len     100: t1 0.000054,	t2 0.000253,	ratio 4.700716
list len     300: t1 0.000151,	t2 0.000756,	ratio 5.016149
list len     500: t1 0.000241,	t2 0.001348,	ratio 5.591028
list len     700: t1 0.000336,	t2 0.001767,	ratio 5.254217
list len     900: t1 0.000430,	t2 0.002273,	ratio 5.287656
list len    1000: t1 0.000477,	t2 0.002526,	ratio 5.299844
list len    3000: t1 0.001417,	t2 0.007579,	ratio 5.347900
list len    5000: t1 0.002358,	t2 0.012665,	ratio 5.370679
list len    7000: t1 0.003344,	t2 0.018058,	ratio 5.400407
list len    9000: t1 0.004256,	t2 0.022734,	ratio 5.341331


-- 
Bay Area Python Interest Group - http://www.baypiggies.net/

Chad Netzer






More information about the Python-list mailing list