Is there a way to affect the range counter in Python?

I am trying to run a python program with a for loop that has an i variable incremented by 1 each time from 1 to the length of my list. In java, my code I'm going to look something like this:

for (int i = 0; i < array.length; i++) { //code goes here i += //the number i want it to go up by } 

This actually affects my counter as intended, and allows me to effectively skip numbers in a for loop, and I want to try running a similar program, but in python. Is there a way to do this using the python built-in function, or do I just need to use a while loop and a counter to simulate this myself if I want python to work this way?

+7
java python
source share
6 answers

To do this, you need a while loop:

 i = 0 while i < len(myArray): # do stuff if special_case: i+= 1 i += 1 
+4
source share

(Disclaimer: never use this code for any remotely serious purpose)

The problem with changing the value of i in your code is this: usually assignments (including added assignment, += ) made for local immutable values ​​are visible only in the local area. The inside of range not in the local area. When you reassign i , the range implementation does not know this.

Usually.

But Python has a built-in module called inspect that provides all the information about your program that you normally would not want to be included at runtime. This includes the values ​​of variables in frames that would otherwise be completely inaccessible.

In violation of good programming principles and laws of nature, we can write a range-like function that breaks the veil of ignorance and steals the value of i from a challenging context, just as Prometheus stole fire from Mount Olympus peak. (Note: remember what happens to Prometheus at the end of this story.)

 import inspect import re def mutable_range(max): x = 0 while x < max: yield x record = inspect.stack()[1] frame = record[0] source_lines = record[4] iterator_name = re.match(r"\s*for (\w+) in mutable_range", source_lines[0]).group(1) peek = frame.f_locals[iterator_name] if peek != x: x = peek else: x += 1 for i in mutable_range(10): print(i) if i == 3: i = -10 if i == -8: i = 6 

Result:

 0 1 2 3 -10 -9 -8 6 7 8 9 

(Disclaimer: The author is not responsible for the use of the code and the subsequent punishment of your arrogance by the eagles that feed your liver for all eternity)

+2
source share

You cannot change the hit counter, but if the step is constant, you can specify it at the beginning:

 # the default >>> range(1, 10) [1, 2, 3, 4, 5, 6, 7, 8, 9] # step 2 >>> range(1, 10, 2) [1, 3, 5, 7, 9] 

You can also take a step back:

 >>> range(10, 0, -1) [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] 

If your case, unfortunately, is not the one where the step is constant during iterations, you will probably need a while loop, as you correctly understood.

+1
source share

In python, it is very similar to Java. You can dynamically increase the counter based on different conditions:

 x = 1 while x < 100: if condition1: x += 1 elif condition2: x += 2 else: x += 3 
+1
source share

In Python, you can create unidirectional iterators with a built-in iter function. In doing so, you can call next to effectively skip the step.

To do this with a few steps, itertools receivers define a consume function:

 def consume(iterator, n): "Advance the iterator n-steps ahead. If n is none, consume entirely." # Use functions that consume iterators at C speed. if n is None: # feed the entire iterator into a zero-length deque collections.deque(iterator, maxlen=0) else: # advance to the empty slice starting at position n next(islice(iterator, n, n), None) 

In this case, we can do:

 import itertools def skip(iterator, n): next(itertools.islice(iterator, n, n), None) range_iter = iter(range(len(ls))) for i in range_iter: # ... if custom_condition: skip(range_iter, 2) # Or any number. 

This also works with direct repeat lists:

 ls_iter = iter(ls) for i in ls_iter: # ... if custom_condition: skip(ls_iter, 3) 

This is super efficient since they use built-in types and functions.

+1
source share

You will be happier with the while loop. You can do something like

 l = list(range(min_count,max_count)) for i in l: 

and change l during the loop. But getting this right is hard. You can also create an iteration object using the skip method and call it during a loop.

 class SkipRange: def __init__(self, minc, maxc, step): self.count = minc self.maxc = maxc self.step = step def __iter__(self): return self def __next__(self): if self.count > self.maxc: raise StopIteration c = self.count self.count += self.step return c def skip(self, num = 1): self.count += num 

Unconfirmed and completely off the top of the bmy head; debugging is left as an exercise to anyone who is annoyed as long as the loops are enough to go this route. I think this is more illustrative of what is happening under the covers.

 s = SkipRange(min_count,max_count) for i in s: # do stuff s.skip(3) #skip next 3 items 

But the while loop is more readable and in most cases simpler.

0
source share

All Articles