33

Possible Duplicate:
Only index needed: enumerate or (x)range?

Which of these would be considered better/clearer/faster/more 'Pythonic'? I don't care about the content of the list L, just how long it is.

a = [f(n) for n, _ in enumerate(L)]

or

a = [f(n) for n in range(len(L))]

If it makes any difference, the function f makes use of len(list) as well.

Community
  • 1
  • 1
Benjamin Hodgson
  • 37,496
  • 16
  • 98
  • 147

4 Answers4

29

Some quick timing runs seem to give the 2nd option using range() a slight edge over enumerate():

timeit a = [f(n) for n, _ in enumerate(mlist)]
10000 loops, best of 3: 118 us per loop

timeit a = [f(n) for n in range(len(mlist))]
10000 loops, best of 3: 102 us per loop

and just for fun using xrange() (Python v2.7.2)

timeit a = [f(n) for n in xrange(len(mlist))]
10000 loops, best of 3: 99 us per loop

I would favor readable code first, then using xrange() if available (i.e., Pre-Python v 3.x), followed by range() and enumerate().

Levon
  • 118,296
  • 31
  • 184
  • 178
  • 4
    enumerate is faster when you want to repeatedly access the list items at their index. When you just want a list of indices, it is faster to to use len() and range/xrange. – ofer.sheffer Nov 20 '16 at 17:31
5

The (x)range solution is faster, because it has less overhead, so I'd use that.

In Python 2.x, use xrange instead of range, because xrange uses less memory, because it doesn't create a temporary list. In Python 3.x, there is only range, which is the less-memory version.

Thus, in Python 2.x, iterating over a range(n) uses O(n) memory temporarily, and iterating over an xrange(n) uses O(1) memory temporarily. Runtime is O(n) for both.

pts
  • 64,123
  • 15
  • 92
  • 159
  • 1
    Is `xrange` a generator object? The [documentation](http://docs.python.org/library/functions.html#xrange) makes no mention of that word, though your description sounds like it is. – Benjamin Hodgson Aug 16 '12 at 15:08
  • 3
    It's not a generator object (i.e. pure Python code with `yield` in its body), but it's equivalent to that, implemented in C. It has a `.next()` method which returns the next value or raises StopIteration, and the `for` loop calls this `.next()` method repeatedly. (Please vote up my answer if you find it useful.) – pts Aug 17 '12 at 12:25
  • nitpick: range does not create a temporary list, it creates a temporary range. So only constant time overhead when using range over xrange. – Peter Zeller Feb 04 '21 at 16:34
  • 1
    @PeterZeller: What `range` returns (list or range object) depends on the Python version (2.x or 3.x). This is correctly reflected in the answer. Your statement *range does not create a temporary list* is incorrect for Python 2.x. I've extended the answer with O(...) for both memory and time. – pts Feb 04 '21 at 17:20
3

I would say that as you aren't using the "_" attribute from the enumarate function then use range as it is more readable that way.

Ctrlspc
  • 1,456
  • 1
  • 14
  • 21
2

Assuming you're using Python 2.x, if you use len(), you should use xrange() as it will avoid creating a list of the numbers in the range.

And in this case, I'd go with len() because you are using the indices, not the items in the list.

kindall
  • 158,047
  • 31
  • 244
  • 289