14

Ss there a simple way to iterate over an iterable object that allows the specification of an end point, say -1, as well as the start point in enumerate. e.g.

for i, row in enumerate(myiterable, start=2): # will start indexing at 2

So if my object has a length of 10, what is the simplest way to to get it to start iterating at index 2 and stop iterating at index 9?

Alternatively, is there something from itertools that is more suitable for this. I am specifically interested in high performance methods.

In addition, when the start option was introduced in 2.6, is there any reason why a stop option was not?

Cheers

JoshieSimmons
  • 2,721
  • 2
  • 14
  • 23
Tom Smith
  • 371
  • 2
  • 3
  • 14

4 Answers4

17
for i, row in enumerate(myiterable[2:], start=2):
   if i>= limit: break
   ...

or

for i,row in itertools.takewhile(lambda (i,val):i < limit,enumerate(myiterable[2:],2)):

to rephrase the other suggestion (note that it will only work if your iterable is a sliceable object)

start,stop = 11,20
my_items = range(100)
for i,row in enumerate(my_items[start:stop],start):
      ....
Kuzeko
  • 1,545
  • 16
  • 39
Joran Beasley
  • 110,522
  • 12
  • 160
  • 179
  • thanks @ Joran Beasley, both are good options, very helpful. I know the obvious response is to the next question is benchmark it yourself, but do you have any inkling if one method you think would be faster than the other? or more preferred with large or small objects etc.? – Tom Smith Feb 11 '14 at 00:23
  • they both short curcuit so they should be equal in terms of execution ... or close to it ... – Joran Beasley Feb 11 '14 at 00:24
17

I think you've misunderstood the 'start' keyword, it doesn't skip to the nth item in the iterable, it starts counting at n, for example:

for i, c in enumerate(['a', 'b', 'c'], start=5):
    print i, c

gives:

5 a
6 b
7 c

For simple iterables like lists and tuples the simplest and fastest method is going to be something like:

obj = range(100)
start = 11
stop = 22
for i, item in enumerate(obj[start:stop], start=start):
    pass
Bi Rico
  • 25,283
  • 3
  • 52
  • 75
  • i understand what it does. i.e iterating over a list of 0-9 starting at 2 will print up to i = 11, c = 9. maybe i phrased the question wrongly. well pointed out though. – Tom Smith Feb 11 '14 at 00:28
  • This seems to be the correct answer then – Kuzeko Oct 04 '21 at 14:07
0

If I'm not going to be using the whole length of the iterable item, I find it easier to use something like:

for i in range(2, len(myiterable)):

instead of enumerate. And then index based on i within the loop. It requires less typing than other approaches that use enumerate.

mikey
  • 1,066
  • 9
  • 17
0

Creating the slice of an iterable object could be expensive. To avoid this, use itertools.islice:

import itertools

for item in itertools.islice('abc', 0, 2):
  print(item)

# will print:
1
2
Oleg Afanasyev
  • 1,754
  • 1
  • 21
  • 16