Manual stepping in python for [duplicate] - python

This question already has answers here:
How do I use a C-style for loop in Python?
(8 answers)
Closed 8 years ago.
In C++, I can do this:
for( int i=0; i<10; ++i ) {
if( something ) i += 3;
}
How can I do the same in Python?
for i in range(10):
# ????

Python for loops work on iterators. If you run on an iterator object that you have bound to a name, you can make the loop skip future values by calling next yourself:
it = iter(iterable) # create our own iterator
for i in it: # loop on it
# do stuff with i
if something:
next(it) # discard the next three values
next(it)
next(it)
You can of course use the return values from the next(i) calls, if you want. This can be handy for some kinds of text data files, where one header line specifies the meaning of the next few data lines.
You should be aware though that if you reach the end of the iterable sequence, next will raise a StopIteration exception. If that happens in the for loop's iteration, it takes care of the exception for you, but if it happens when you call next yourself, it will not be. If an unexpected end of the data is not an unrecoverable error, you will probably want to use a try/except block to suppress the exception.

The basic equivalent in Python is this:
for i in range(start, stop, increment):
do_something(i)
That means that the following codes behave identically:
for (int i = 10; i >= 1; i -= 2) {
doSomething(i);
}
for i in range(10, 0, -2):
do_something(i)
Normally, we want to start at zero, increment by one, and stop at a certain number, which leads to the shortcut:
for i in range(stop):
do_something(i)
If you want to modify 'i', and have it affect how many times you loop, you must use a 'while' loop:
i = 0
while i <= 10:
if (something):
i += 3
i += 1
...which is what you should also be doing in C++. A 'for' loop is for repeating a definite number of times. If you're modifying the counter inside the loop, then the loop is no longer definite and you should be using a while loop instead, since it's semantically a better fit.

i=0
while i<10:
if something:
i += 3
else:
i += 1

Related

Python how to make loop that can be "for" or "while", depending on if upper limit is present

I have a use case where I need to repeat some block of code:
Sometimes I need to repeat the code block a finite number of times
Sometimes I need to repeat the code block indefinitely.
I am wondering, is there some Python built-in way to:
No limit supplied --> code block is repeated via something like a while loop
Limit supplied --> code block is repeated via something like a for loop
Note: I know I can use an if statement (depending on if upper limit is present), and switch between a for or while loop. I am trying to not have the code block repeated twice, or it broken out into another function.
Current Implementation
I wrote the below flawed (see below) for_while_hybrid.py using Python 3.8.2.
from typing import Iterator
def iter_for_while(num_yield: int = None) -> Iterator[int]:
"""Generate an incrementing counter.
This enables one to make a for loop or a while loop, depending on args.
Args:
num_yield: Number of times to yield.
If left as None, the generator makes a while loop
If an integer, the generator makes a for loop
"""
counter = 0
condition = True if num_yield is None else counter < num_yield
while condition:
yield counter
counter += 1
if num_yield is not None:
condition = counter < num_yield
upper_limit = 5
for _ in iter_for_while(upper_limit):
print("Some code block") # Run 5 times
for _ in iter_for_while():
print("Some code block") # Run infinitely
This implementation works.
The downside is, if run for a very long time, I am worried the counter will take up lots of memory, or will eventually max out. My computer is 64-bit, so sys.maxsize = 2 ** 63 - 1 = 9,223,372,036,854,775,807.
Just use count or range, depending on the upper bound:
from itertools import count
def iter_for_while(bound=None):
return count() if bound is None else range(bound)
use a while loop but you can say while X < Y: do something and then X += 1
this means you can control how many times it repeats with X or if you want it indefinitely then don't say X + 1

Is there a way to do conditionals inside Python (3) for loops?

Coming from primarily coding in Java and wanted to know if Python could use conditionals and different kinds of incrementing inside its for loops like Java and C can. Sorry if this seems like a simple question.
i.e.:
boolean flag = True
for(int i = 1; i < 20 && flag; i *= 2) {
//Code in here
}
Not directly. A for loop iterates over a pre-generated sequence, rather than generating the sequence itself. The naive translation would probably look something like
flag = True
i = 1
while i < 20:
if not flag:
break
...
if some_condition:
flag = False
i *= 2
However, your code probably could execute the break statement wherever you set flag to False, so you could probably get rid of the flag altogether.
i = 1
while i < 20:
...
if some_condition:
break
i *= 2
Finally, you can define your own generator to iterate over
def powers_of_two():
i = 1
while True:
yield i
i *= 2
for i in powers_of_two():
...
if some_condition:
break
The for loops in Python are not like loops in C. They are like the for-each loops applied to iterables that came out in Java 7:
for (String name: TreeSet<String>(nameList) ) {
//Your code here
}
If you want control over your iterator variable, then a while or for loop with a break in it is probably the cleanest way to achieve that kind of control.
This might be a good time to look into finding time to do a tutorial on Python comprehensions. Even though they are not directly applicable to your question, that is the feature that I appreciate most having come from Java about five years ago.
You can use range() if you have the step as some constant increment (like i++,i+=10,etc). The syntax is -
range(start,stop,step)
range(start, stop, step) is used as a replacement for for (int i = start; i < stop; i += step). It doesn't work with multiplication, but you can still use it (with break) if you have something like i < stop && condition.
The equivalent loop for the one you mentioned in question can be =>
for(int i=0;i<20;i*=2) // C/C++ loop
# Python - 1
i = 0
while i < 20 : # Equivalent python loop
# Code here
i*=2
If you are willing to use flag as well as a condition, you will have to do it as =>
// C/C++
bool flag = true;
for(int i=0;i<20&&flag;i*=2) // C/C++ loop
# Python - 1
i,flag = 1,True
while not flag and i < 20 : # Equivalent python loop
# Code here
i*=2
Hope this helps !
In a sense, but it's not quite as simple as it is with JS and Java.
Here is your example written in Python using a while loop with two conditions. Also note that in Python while loops, you cannot assign or increment the index in the loop's declaration.
boolean_flag = True
i = 1
while (i < 20 and boolean_flag):
i *= 2
# Code in here
The answers above are good and efficient for what you ask, but I'll give my idea of how I would do it.
max = 20
for i in range(0, max/2):
c = i * 2
if flag:
#Do work.
break
or to make it shorter:
max = 20
for i in range(0, max, 2):
if flag:
#Do work.
break
Firstly, in python you cannot increment using the increment operator as in C++, or Java, e.x, x++ or --x. A for loop in Python works over an iterator (For example, List, String, etc.)
PYTHON FOR LOOPS:
A for loop is used for iterating over a sequence (that is either a list, a tuple, a dictionary, a set, or a string`).
This is less like the for keyword in other programming languages, and works more like an iterator method as found in other object-orientated programming languages.
With the for loop we can execute a set of statements, once for each item in a list, tuple, set etc.
Example
Print each fruit in a fruit list:
fruits = ["apple", "banana", "cherry"]
for x in fruits:
print(x)
will print:
apple
banana
cherry
Example
Do not print banana:
fruits = ["apple", "banana", "cherry"]
for x in fruits:
if x == "banana":
continue
print(x)
PYTHON CONDITIONALS:
In python the keyword for false values is False, and that for true values is True
Like C++ or Java, you can use == to compare values. But unlike Java, where there is strict type-checking and the condition needs to be a Boolean Statement, in Python:
Almost any value is evaluated to True if it has some sort of content.
Any string is True, except empty strings.
Any number is True, except 0.
Any list, tuple, set, and dictionary are True`, except empty ones.
In fact, there are not many values that evaluates to False, except empty values, such as (), [], {}, "", the number 0, and the value None. And of course the value False evaluates to False.
The following will return False:
bool(False)
bool(None)
bool(0)
bool("")
bool(())
bool([])
bool({})
One more value, or object in this case, evaluates to False, and that is if you have an object that is made from a class with a __len__ function that returns 0orFalse`:
class myclass():
def __len__(self):
return 0
myobj = myclass()
print(bool(myobj))
You use while for flag and condition and increment inside loop
i = 1
while flag and i < 20:
# code here
i = i*2
Sure, but you may need to do some things yourself.
Python provides the range() class which produces an interable sequence of values with an optional step increment.
for i in range(1, 20, 2):
# do the things
# here, i starts at 1, and increments by 2 each loop stops at >= 20
If you want to do something more complicated like i *= 2, You have two options:
use a while loop and increment the values yourself
write a custom generator like range() that implements such a thing.
Example generator:
def range_step_mult(start, stop, step):
while start < stop:
yield start
start *= step
for i in range_step_mult(1, 100, 2):
print(i)
Note the use of the yield keyword here. This is VERY important for performance over large ranges, especially if the iterable object is on the larger side. Using the keyword here allows Python to simply deal with one object at a time as opposed to generating all that stuff in memory before it even starts working on it.
You can use conditionals within the for loop, and you can use the break and continue keywords to control the loop flow to some level. That being said, the loop is generated outside of this block, so you can't change the step or something mid loop.
While loops are a different story entirely and you can alter the step as much as you want as you're the one incrementing it in the first place.
Example while loop:
i = 1
while i < 100
if i % 2 == 0:
i *= 2
else:
i += 1
In common with several other answers, here is how I would actually translate that code:
boolean_flag = True
i = 1 # actually I wouldn't use i as a variable name, but whatever.
while i < 20 and boolean_flag:
# code goes here
i *= 2
I would also consider using a for loop, which might look something like this:
from itertools import takewhile, count
boolean_flag = True
for i in takewhile(lambda i: i < 20, map(lambda x: 2**x, count())):
# code goes here
if not boolean_flag:
break
But having considered both, I prefer the while loop. And in practice I very rarely actually need a flag defined across a loop like that. Normally you can either break from the loop immediately you detect the condition that would cause you to set the flag, or else use logic like this:
boolean_flag = something()
something_that_has_to_happen_after_regardless_of_flag_value()
if not boolean_flag:
break
The need for boolean "break" flags is mostly (not wholly) a result of trying to write all your loops with no break in them, but there's no particular benefit to doing that.
It might be possible to salvage the for loop, or at least learn a few things about Python, by playing around with other ways to write what comes after for. Like lambda i: i < 20 could be (20).__gt__, but that's breathtakingly ugly in its own way. Or map(lambda is always a warning sign, and in this case map(lambda x: 2**x, count()) could be replaced with (2**x for x in count()). Or you can use functools.reduce to change the exponentiation back to multiplication, but it's unlikely to be worth it. Or you can write a generator function, but that's a chunk more boilerplate.
Supposing I know that the base-2 logarithm of 20 can only be so big, but I don't want to make myself a hostage to stupid off-by-one errors, I could write something like:
for i in (2**x for x in range(10)):
if not i < 20:
break
Or to get rid of all of the "clever" stuff:
for x in range(10):
i = 2 ** x
if not (i < 20 and boolean_flag):
break
But again, this isn't really solving the basic issue that for loops are intended for when you have an iterable containing the right values, and in Python you need to pull several things together to come up with the right iterable for this case (especially if you want to write 20 rather than the logarithm of 20). And that's even before you deal with the flag. So, in general you use a for loop when you have something to iterate over, or can easily produce something to iterate over, and use a while loop for more general looping based on mutating local variables.
Frankly for those specific numbers you might as well write for i in (1, 2, 4, 8, 16) and have done with it!

skip iterations in for loop in python?

I have programmed in C++ earlier but I am new to Python. I searched for this but i was not able to find the appropriate answer. In C++, I can do:
for(int i=0; i<10;i++)
{
i+=5;
std::cout<<i<<std::endl
}
The values of i would be 5 and 11. But in python if i do:
for i in range(0,10):
i+=5
print i
The value of i does update for that iteration of loop, but in the next iteration, it will become 1.
While I do understand that in python, after each iteration, i will contain the next value in the tuple/list generated by range, but is there any way I can make it skip iterations like in C++? I really don`t want to use the next() function 5 times
EDIT: I can use the third parameter of range function for general use, but what if I want to skip some iterations for say if only a certain condition is true. eg
for(int i=0; i<10;i++)
{
if(i%2)i+=1;
std::cout<<i<<std::endl
}
If you want to skip iterations when a condition is true, then use continue:
for i in range(10):
if i % 2:
continue
print(i)
You can use a regular while loop. it will look less nice but it does the job.
for example:
i = 0
while i < 100:
print i
if i % 2 == 0:
i += 5
i+=1
I know what you were thinking, but there's something built-in for python that allows you to set the iteration step within the range() function. Here is the official Python Documentation on range().
In essence, to skip x after each iteration, you would do:
for i in range(start, stop, x + 1):
# functions and stuff
Hope this helped.

How to change for-loop iterator variable in the loop in Python?

I want to know if is it possible to change the value of the iterator in its for-loop?
For example I want to write a program to calculate prime factor of a number in the below way :
def primeFactors(number):
for i in range(2,number+1):
if (number%i==0)
print(i,end=',')
number=number/i
i=i-1 #to check that factor again!
My question : Is it possible to change the last two line in a way that when I change i and number in the if block, their value change in the for loop!
Update: Defining the iterator as a global variable, could help me? Why?
Short answer (like Daniel Roseman's): No
Long answer: No, but this does what you want:
def redo_range(start, end):
while start < end:
start += 1
redo = (yield start)
if redo:
start -= 2
redone_5 = False
r = redo_range(2, 10)
for i in r:
print(i)
if i == 5 and not redone_5:
r.send(True)
redone_5 = True
Output:
3
4
5
5
6
7
8
9
10
As you can see, 5 gets repeated. It used a generator function which allows the last value of the index variable to be repeated. There are simpler methods (while loops, list of values to check, etc.) but this one matches you code the closest.
No.
Python's for loop is like other languages' foreach loops. Your i variable is not a counter, it is the value of each element in a list, in this case the list of numbers between 2 and number+1. Even if you changed the value, that would not change what was the next element in that list.
The standard way of dealing with this is to completely exhaust the divisions by i in the body of the for loop itself:
def primeFactors(number):
for i in range(2,number+1):
while number % i == 0:
print(i, end=',')
number /= i
It's slightly more efficient to do the division and remainder in one step:
def primeFactors(number):
for i in range(2, number+1):
while True:
q, r = divmod(number, i)
if r != 0:
break
print(i, end=',')
number = q
The only way to change the next value yielded is to somehow tell the iterable what the next value to yield should be. With a lot of standard iterables, this isn't possible. however, you can do it with a specially coded generator:
def crazy_iter(iterable):
iterable = iter(iterable)
for item in iterable:
sent = yield item
if sent is not None:
yield None # Return value of `iterable.send(...)`
yield sent
num = 10
iterable = crazy_iter(range(2, 11))
for i in iterable:
if not num%i:
print i
num /= i
if i > 2:
iterable.send(i-1)
I would definitely not argue that this is easier to read than the equivalent while loop, but it does demonstrate sending stuff to a generator which may gain your team points at your next local programming trivia night.
It is not possible the way you are doing it. The for loop variable can be changed inside each loop iteration, like this:
for a in range (1, 6):
print a
a = a + 1
print a
print
The resulting output is:
1
2
2
3
3
4
4
5
5
6
It does get modified inside each for loop iteration.
The reason for the behavior displayed by Python's for loop is that, at the beginning of each iteration, the for loop variable is assinged the next unused value from the specified iterator. Therefore, whatever changes you make to the for loop variable get effectively destroyed at the beginning of each iteration.
To achieve what I think you may be needing, you should probably use a while loop, providing your own counter variable, your own increment code and any special case modifications for it you may need inside your loop. Example:
a = 1
while a <= 5:
print a
if a == 3:
a = a + 1
a = a + 1
print a
print
The resulting output is:
1
2
2
3
3
5
5
6
Yes, we can only if we dont change the reference of the object that we are using. If we can edit the number by accessing the reference of number variable, then what you asked is possible.
A simple example:
a=[1,2,3]
a=a+[4]==>here, a new object is created which plots to different address.
a+=[4]==>here , the same object is getting updated which give us the desired result.
number=10
list1=list(range(2,number+1))
# list1
for i in list1:
print(list1,i)
if (number%i==0):
print(i,end=',')
number=number//i #we can simply replace it with number//=i to edit the number without changing the reference or without creating a new object.
try:
[list1.pop() for i in range(10,0,-1) if(i>number)]
#here pop() method is working on the same object which list created by number refers. so, we can able to change the iterable in the forloop.
except:
continue
i=i-1 #to check that factor again!

Looping from 1 to infinity in Python

In C, I would do this:
int i;
for (i = 0;; i++)
if (thereIsAReasonToBreak(i))
break;
How can I achieve something similar in Python?
Using itertools.count:
import itertools
for i in itertools.count(start=1):
if there_is_a_reason_to_break(i):
break
In Python 2, range() and xrange() were limited to sys.maxsize. In Python 3 range() can go much higher, though not to infinity:
import sys
for i in range(sys.maxsize**10): # you could go even higher if you really want
if there_is_a_reason_to_break(i):
break
So it's probably best to use count().
def to_infinity():
index = 0
while True:
yield index
index += 1
for i in to_infinity():
if i > 10:
break
Simplest and best:
i = 0
while not there_is_reason_to_break(i):
# some code here
i += 1
It may be tempting to choose the closest analogy to the C code possible in Python:
from itertools import count
for i in count():
if thereIsAReasonToBreak(i):
break
But beware, modifying i will not affect the flow of the loop as it would in C. Therefore, using a while loop is actually a more appropriate choice for porting that C code to Python.
Reiterating thg435's comment:
from itertools import takewhile, count
def thereIsAReasonToContinue(i):
return not thereIsAReasonToBreak(i)
for i in takewhile(thereIsAReasonToContinue, count()):
pass # or something else
Or perhaps more concisely:
from itertools import takewhile, count
for i in takewhile(lambda x : not thereIsAReasonToBreak(x), count()):
pass # or something else
takewhile imitates a "well-behaved" C for loop: you have a continuation condition, but you have a generator instead of an arbitrary expression. There are things you can do in a C for loop that are "badly behaved", such as modifying i in the loop body. It's possible to imitate those too using takewhile, if the generator is a closure over some local variable i that you then mess with. In a way, defining that closure makes it especially obvious that you're doing something potentially confusing with your control structure.
If you want to use a for loop, it's possible to combine built-in functions iter (see also this answer) and enumerate for an infinite for loop which has a counter. We're using iter to create an infinite iterator and enumerate provides the counting loop variable. The start value is zero by default, but you can set a different start value with the start argument.
for i, _ in enumerate(iter(bool, True), start=1):
input(i)
Which prints:
1
2
3
4
5
...
If you're doing that in C, then your judgement there is as cloudy as it would be in Python :-)
For a loop that exits on a simple condition check at the start of each iteration, it's more usual (and clearer, in my opinion) to just do that in the looping construct itself. In other words, something like (if you need i after loop end):
int i = 0;
while (! thereIsAReasonToBreak(i)) {
// do something
i++;
}
or (if i can be scoped to just the loop):
for (int i = 0; ! thereIsAReasonToBreak(i); ++i) {
// do something
}
That would translate to the Python equivalent:
i = 0
while not there_is_a_reason_to_break(i):
# do something
i += 1
Only if you need to exit in the middle of the loop somewhere (or if your condition is complex enough that it would render your looping statement far less readable) would you need to worry about breaking.
When your potential exit is a simple one at the start of the loop (as it appears to be here), it's usually better to encode the exit into the loop itself.
def infinity():
i=0
while True:
i+=1
yield i
for i in infinity():
if there_is_a_reason_to_break(i):
break
def natural_numbers():
yield from map(sum, enumerate(iter(int,1)))
for i in natural_numbers():
if there_is_a_reason_to_break(i):
break;

Categories