4

I want to step the loop iterator explicitly inside the loop. Is there a 'nicer' way to do this than:

idx = iter(range(0, 10))

for i in idx:
   print i

   if i == 5:
      print "consuming %i in step %i" % (next(idx), i)

Edit: I wander if there is a way to get access to the loop-iterator other than defining it explicitly as in my example.

Thanks!

5
  • 3
    What's wrong with next(idx)? Isn't it explicit and nice enough? Commented Feb 13, 2011 at 8:22
  • @eumiro: Not if idx isn't already an iterator (eg. a list). It's also very uncommon practice to take the next of an iterator while you're iterating over it. I'd strongly recommend against it. Commented Feb 13, 2011 at 9:26
  • I am concerned about the head of the loop; usually one would see something like for i in range(0, 10) - but then I don't get access to the iterator-object... Commented Feb 13, 2011 at 13:34
  • Related: stackoverflow.com/questions/4810160/… Commented Oct 6, 2015 at 12:36
  • also related, and with a more thorough explanation on why this works: stackoverflow.com/a/46522452/6053327 Commented Oct 2, 2017 at 9:52

2 Answers 2

3
data = list(range(10))

it = iter(data)
for i in it:
   if i==5:
       j = it.next()
       print "Consuming {0},{1}".format(i,j)
   else:
       print i

results in

0
1
2
3
4
Consuming 5,6
7
8
9
Sign up to request clarification or add additional context in comments.

3 Comments

I am concerned about the head of the loop. Is the iterator of a for-loop exposed in some way - or do I have to state the iterator explicitly as in my (and your) example to get access to it? I see that asking for a 'nicer' way in general was not very clearly...
So far as I am aware there is no way to directly access the loop iterator; you need to explicitly create it and keep a copy beforehand.
+1 for a good point: you can steal further items from your iterator, even if you are inside the cycle. NOTE: you may get a StopIteration which terminates the loop apparently clean way, but this may put you into an inconsistent state with your program logic.
0

You could define a generator to yield elements from the iterator singly or in pairs. This keeps the for-loop nice and simple, while isolating the filtering logic in the generator.

def my_filter(iterable):
    result=[]
    for i in iterable:
        result.append(i)
        if i==5:
            continue
        yield result
        result=[]        

idx = iter(range(0, 10))

for i in my_filter(idx):
    print i

4 Comments

I want to consume all elements; in some cases I just need to consume them in the same iteration... Sometimes the elements I am iterating need to be consumed in pairs, usually they are treated as 'single'.
@MrPugh: You can modify the generator (my_filter), so that it yields an object that contains either a single element from idx or multiple elements from idx. Ideally, the for-loop should process those objects homogenously -- it shouldn't care if the object contains a single element from idx or multiple elements.
I've modified the code to show what I mean. Above, I just use a list to collect the single, or paired elements. Depending on your problem, you may want to use some other container, such as a named tuple, or dict, or maybe a custom class...
I like that my_filter would generate my pairings; however my actual code is a bit more complicated - and the continue in the my_filter-loop would not work nicely. So it turns me back to the original question: how can I consume the next element within the same iteration... Maybe creating the iterator-object explicitly and using next() as in my initial example is the way to go for me... Thanks for you effort!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.