8

What is faster, a for loop using enumerate or using xrange?

EDIT: I have tested, and I just see minimal differences.

ichigo
  • 317
  • 2
  • 6
  • 17
  • 10
    They are not really interchangeable. What are you trying to do? Can you paste a code sample? – Adam Matan Jan 31 '11 at 15:57
  • 4
    Why not test it ([after determining that it matters](http://tinyurl.com/knuth-premature))? – Fred Nurk Jan 31 '11 at 16:04
  • 5
    Wow, downvote heaven over here. Let's wait a little for an improved question. Perhaps the poster needs an answer as to why this question is difficult to answer... Let's be a little more welcoming to this new user and help him along on his first post. – Benjamin Jan 31 '11 at 16:09
  • 2
    @Adam: They are if you want to have an index variable handy while you iterate. – Marcelo Cantos Jan 31 '11 at 16:09
  • @Marcelo that's what `enumerate` is for. – Josh Bleecher Snyder Jan 31 '11 at 17:13
  • It's like asking "which gas will make my limousine go faster?" ... if you care about speed make the car lighter or get a different one. – Jochen Ritzel Jan 31 '11 at 17:18
  • @Josh: I don't know what point you are trying to make. My point was that both enumerate and xrange will provide an index as you iterate, and thus are somewhat interchangeable. Do you disagree with this? – Marcelo Cantos Feb 01 '11 at 02:20
  • 2
    @Jochen: High-octane gas will make some cars go faster, and using the right mixture is likely to be much cheaper that buying a different car. As for the question, I think it's perfectly reasonable to ask which is faster. Sometimes little things like this can make a big difference to performance-critical sections of code. In JavaScript, for instance, choosing the right looping construct can make a [huge difference](http://benhollis.net/blog/2009/12/13/investigating-javascript-array-iteration-performance/). – Marcelo Cantos Feb 01 '11 at 02:24
  • @Marcelo they are indeed somewhat interchangeable; I agree with this. I just think that enumerate is more Pythonic, easier to read, etc. But I think that, in the spree of voted comments, I lost the thread of the conversation, so my remark was a little off topic. Sorry. :) – Josh Bleecher Snyder Feb 01 '11 at 02:45

3 Answers3

8

Enumerate is slightly faster. Tested in Python 3:

>>>import pygame
>>>pygame.init()
>>>clock = pygame.time.Clock()
>>>a = list(range(100000))
>>>def do_with_range():
...    clock.tick()
...    k = 0
...    for i in range(len(a)):
...        k += a[i]
...    print(clock.tick())
>>>def do_with_enumerate():
...    clock.tick()
...    k = 0
...    for i, j in enumerate(a):
...        k += j
...    print(clock.tick())
>>>do_with_range()
23
>>>do_with_enumerate()
21

If a wouldn't be a list, but a generator, it would be significantly faster to use enumerate (74ms using range, 23ms using enumerate).

Colin Emonds
  • 765
  • 4
  • 18
  • The question was actually asking about `xrange`, not `range` – Richard Levasseur Jan 31 '11 at 16:28
  • 8
    In Python 3 xrange got replaced by range and range is a generator now. This is also why i manually did list(range()). Thus, the results in Python 2 using xrange would be similar. – Colin Emonds Jan 31 '11 at 16:30
  • 1
    Okay, I tested it in Python 2 as well. For obscure reasons, Python 2 is a hell of a lot faster than Python 3, and the xrange and enumerate versions are of the same speed: 14ms. (Shouldn't one expect later versions of the language to be faster than previous ones? But well...). – Colin Emonds Jan 31 '11 at 16:35
  • 2
    And yet it's still faster to use a local that you increment rather than either of these methods. Enumerate *is* the Pythonic way, but unpacking tuples is slower than incrementing locals, and so it will probably always be slower (although only marginally so). – Nick Bastin Jan 31 '11 at 19:45
  • @Nick: Not to mention that the difference will be ridiculous, if noticeable at all, even a noticeable difference wouldn't justify the extra code and ugliness unless perhaps in an inner loop (which you should propably just write in Cython if speed is *that* important). –  Jan 31 '11 at 20:10
  • 1
    @delnan: well, this actually comes into play using LLVM, where JIT optimizing += is quite different than JIT optimizing a function result being unpacked into two locals. Not that stackoverflow comments are the place to discuss the finer details of python efficiency.. :-) But suffice it to say that the global resource consumption of using enumerate() on a cluster can actually be a significant disadvantage compared to +=. – Nick Bastin Jan 31 '11 at 20:39
  • according to this page http://pythonfasterway.uni.me/ enumerate is faster than xrange. It is true. I tried it too. – wookie Apr 20 '15 at 11:38
6

You can use the timeit module in the standard library to compare both. The timeit.timeit() function used below takes a statement that it runs 1'000'000 times and returns the total time in seconds. In this test enumerate() is slightly slower.

>>> import timeit
>>> timeit.timeit('for i in xrange(100): a[i]', 'a = list(xrange(100))')
7.2920000553131104
>>> timeit.timeit('for i, o in enumerate(a): o', 'a = list(xrange(100))')
10.359999895095825
>>> timeit.timeit('for i in xrange(100): a[i] + 1', 'a = list(xrange(100))')
10.380000114440918
>>> timeit.timeit('for i, o in enumerate(a): o + 1', 'a = list(xrange(100))')
13.514999866485596
jd.
  • 10,678
  • 3
  • 46
  • 55
0

Mu.

For loops can use both enumerate and xrange at the same time, though it would be silly. The enumerate function adds an index so you can tell what the index of an item in your iterable is. The xrange function returns an iterable full of numbers. Use it when you want to do something a certain number of times, instead of for each element in an iterable.

Examples:

for idx, element in ['foo', 'bar', 'baz']:
    print idx, element

for idx in xrange(3):
    print idx
nmichaels
  • 49,466
  • 12
  • 107
  • 135