Python arbitrarily increments an iterator inside a loop

I'm probably wrong, but I was wondering how to do this in python.

First c code:

int i; for(i=0;i<100;i++){ if(i == 50) i = i + 10; printf("%i\n", i); } 

Okay, so we never see the 50s ...

My question is: how can I do something like this in python? For example:

 for line in cdata.split('\n'): if exp.match(line): #increment the position of the iterator by 5? pass print line 

Thanks to my limited experience in python, I have only one solution, enter a counter and another if statement. interrupt the loop until the counter reaches 5 after exp.match (line) is true.

There should be a better way to do this, hopefully one that does not involve importing another module.

Thanks in advance!

+41
python iterator
Sep 24 '09 at 23:11
source share
8 answers

Python has a fantastic package called itertools .

But before I get it, this will serve as a good explanation of how the iterative protocol is implemented in Python. When you want to provide iteration over your container, you specify the class method __iter__() , which provides the type of iterator . Understanding Python for a statement is a good article that describes how the for-in statement actually works in Python and gives a good overview of how iterators work.

Take a look at the following:

 >>> sequence = [1, 2, 3, 4, 5] >>> iterator = sequence.__iter__() >>> iterator.next() 1 >>> iterator.next() 2 >>> for number in iterator: print number 3 4 5 

Now back to itertools . The package contains functions for various iteration purposes. If you ever need to complete a special sequence, this is the first place you need to pay attention to.

Below you can find the Recipes section, which contains recipes for creating an advanced toolbox using existing itertools as building blocks.

And there is an interesting function that does exactly what you need:

 def consume(iterator, n): '''Advance the iterator n-steps ahead. If n is none, consume entirely.''' collections.deque(itertools.islice(iterator, n), maxlen=0) 

Here is a quick, readable example of how it works (Python 2.5):

 >>> import itertools, collections >>> def consume(iterator, n): collections.deque(itertools.islice(iterator, n)) >>> iterator = range(1, 16).__iter__() >>> for number in iterator: if (number == 5): # Disregard 6, 7, 8, 9 (5 doesn't get printed just as well) consume(iterator, 4) else: print number 1 2 3 4 10 11 12 13 14 15 
+41
Sep 25 '09 at 0:27
source share

itertools.islice :

 lines = iter(cdata.splitlines()) for line in lines: if exp.match(line): #increment the position of the iterator by 5 for _ in itertools.islice(lines, 4): pass continue # skip 1+4 lines print line 

For example, if exp , cdata :

 exp = re.compile(r"skip5") cdata = """ before skip skip5 1 never see it 2 ditto 3 .. 4 .. 5 after skip 6 """ 

Then output:

 before skip
 5 after skip
 6 

C language implementation of the Cython example

 i = 0 while i < 100: if i == 50: i += 10 print i i += 1 

As @ [Glenn Maynard] pointed out in a comment , if you need to make very large transitions like me + = 100000000, then you should use an explicit while , and not just skip the steps in the for loop.

Here's an example that uses an explicit while instead of islice :

 lines = cdata.splitlines() i = 0 while i < len(lines): if exp.match(lines[i]): #increment the position of the iterator by 5 i += 5 else: print lines[i] i += 1 

This example produces the same result as the previous islice example.

+16
Sep 25 '09 at 0:42
source share

If you do this with numbers, a list comprehension can be implemented:

 for i in [x for x in range(0, 99) if x < 50 and x > 59]: print i 

Moving the iterator forward is a bit trickier. I suggest setting up your list in advance if you do not want to use the counter approach, perhaps by splitting cdata, then work out the indices of the corresponding row and delete this row and the following. In addition, you are stuck with a counter approach that is not as unpleasant as you do to be honest.

Another variant:

 iterator = iter(cdata.split('\n')) for line in iterator: if exp.match(line): for i in range(0, 5): try: iterator.next() except StopIteration: break else: print line 
+2
Sep 24 '09 at 23:24
source share

Not quite sure that I am following your thought process, but there is something to eat here.

 for i in range(len(cdata.split('\n'))): if i in range(50,60): continue line = cdata[i] if exp.match(line): #increment the position of the iterator by 5? pass print line 

Not sure what you really are after, but the range (len (..)) should help you.

+1
Sep 24 '09 at 23:22
source share

You can reset the values ​​from the iterator

 def dropvalues(iterator, vals): for i in xrange(vals): iterator.next() 

Now just make sure you have an iterator object to work with lines = iter(cdata.split('\n')) ; and flip it over.

+1
Sep 24 '09 at 23:31
source share

Perhaps with genexps. Not really, but ...

Something like that:

 >>> gx = (line for line in '1 2 x 3 4 5 6 7 x 9 10 11 12 x 1'.split('\n')) >>> for line in gx: ... if line == 'x': ... for i in range(2): ... line = gx.next() ... print line 

The only problem is to ensure that gx can be as follows () - ed. The above example specifically throws an exception due to the last x.

0
Sep 24 '09 at 23:49
source share

for your example, since you are working with lists (indexed sequences) and not with iterators, I would recommend the following:

 lines = cdata.split("\n") for line in lines[:50]+lines[60:]: print line 

which is not the most efficient, since it potentially creates 3 new lists (but if the missing part is larger than the processed part, it may be more efficient than other options), but it is quite clean and explicit.

If you don't mind using the itertools module, you can easily convert lists in sequence:

 from itertools import chain, islice for line in chain(islice(lines, None, 50), islice(lines, 60,None)): print line 
0
Sep 25 '09 at 12:21
source share

I can't make out the question, which is changing well, because there is this block of confusing and irrelevant C. code. Delete it.

Focusing only on Python code and on the question of how to skip 5 lines ...

 lineIter= iter( cdata.splitlines() ) for line in lineIter: if exp.match(line): for count in range(5): line = lineIter.next() print line 
-5
Sep 25 '09 at 0:41
source share



All Articles