Check statement for a loop only once - python

Let’s say I have following simple code:
useText = True
for i in range(20):
if useText:
print("The square is "+ str(i**2))
else:
print(i**2)
I use the variable useText to control which way to print the squares. It doesn’t change while running the loop, so it seems inefficient to me to check it every time the loop runs. Is there any way to check useText only once, before the loop, and then always print out according to that result?
This question occurs to me quite often. In this simple case of course it doesn’t matter but I could imagine this leading to slower performance in more complex cases.

The only difference that useText accomplishes here is the formatting string. So move that out of the loop.
fs = '{}'
if useText:
fs = "The square is {}"
for i in range(20):
print(fs.format(i**2))
(This assumes that useText doesn't change during the loop! In a multithreaded program that might not be true.)

The general structure of your program is to loop through a sequence and print the result in some manner.
In code, this becomes
for i in range(20):
print_square(i)
Before the loop runs, set print_square appropriately depending on the useText variable.
if useText:
print_square = lambda x: print("The square is" + str(x**2))
else:
print_square = lambda x: print(x**2)
for i in range(20):
print_square(i)
This has the advantage of not repeating the loop structure or the check for useText and could easily be extended to support other methods of printing the results inside the loop.

If you are not going to change the value of useText inside the loop, you can move it outside of for:
if useText:
for i in range(20):
print("The square is "+ str(i**2))
else:
for i in range(20):
print(i**2)

We can move if outside of for since you mentioned useText is not changing.

If you write something like this, you're checking the condition, running code, moving to the next iteration, and repeating, checking the condition each time, because you're running the entire body of the for loop, including the if statement, on each iteration:
for i in a_list:
if condition:
code()
If you write something like this, with the if statement inside the for loop, you're checking the condition and running the entire for loop only if the condition is true:
if condition:
for i in a_list:
code()
I think you want the second one, because that one only checks the condition once, at the start. It does that because the if statement isn't inside the loop. Remember that everything inside the loop is run on each iteration.

Related

Best way in python to check if a loop is not executed

The title might be misleading, so here is a better explanation.
Consider the following code:
def minimum_working_environment(r):
trial=np.arange(0,6)[::-1]
for i in range(len(trial)):
if r>trial[i]:
return i
return len(trial)
We see that if r is smaller than the smallest element of trial, the if clause inside the loop is never executed. Therefore, the function never returns anything in the loop and returns something in the last line. If the if clause inside the loop is executed, return terminates the code, so the last line is never executed.
I want to implement something similar, but without return, i.e.,
def minimum_working_environment(self,r):
self.trial=np.arange(0,6)[::-1]
for i in range(len(self.trial)):
if r>trial[i]:
self.some_aspect=i
break
self.some_aspect=len(self.trial)
Here, break disrupts the loop but the function is not terminated.
The solutions I can think of are:
Replace break with return 0 and not check the return value of the function.
Use a flag variable.
Expand the self.trial array with a very small negative number, like -1e99.
First method looks good, I will probably implement it if I don't get any answer. The second one is very boring. The third one is not just boring but also might cause performance problems.
My questions are:
Is there a reserved word like return that would work in the way that I want, i.e., terminate the function?
If not, what is the best solution to this?
Thanks!
You can check that a for loop did not run into a break with else, which seems to be what you're after.
import numpy as np
def minimum_working_environment(r):
trial = np.arange(0, 6)[::-1]
for i in range(len(trial)):
if r > trial[i]:
return i
return len(trial)
def alternative(r):
trial = np.arange(0, 6)[::-1]
for i in range(len(trial)):
if r > trial[i]:
break
else:
i = len(trial)
return i
print(minimum_working_environment(3))
print(minimum_working_environment(-3))
print(alternative(3))
print(alternative(-3))
Result:
3
6
3
6
This works because the loop controlling variable i will still have the last value it had in the loop after the break and the else will only be executed if the break never executes.
However, if you just want to terminate a function, you should use return. The example I provided is mainly useful if you do indeed need to know if a loop completed fully (i.e. without breaking) or if it terminated early. It works for your example, which I assume was exactly that, just an example.

adding to list in while loop

I have a problem with loop for game I am writing.
most of game's code is in while loop, the part I am concerned looks more or less like that:
while True:
lista=[]
somenumber=randrange(5,20)
lista.append(somenumber)
break
not a real code but shows idea. I want the list to expand each time the loop runs, but instead the list holds only number from current loop. Any idea how I can do it? I would like the list to expand witch each run of the loop.
You must mive this
lista=[]
Outside of your loop, otherwise you init that variable each iteration. Also you need to delete
break
As it breaks after first iteration. From other hand you need
some logic to stop the loop otherwise you will be spinning till out of memory
Define the list outside of the loop,
Each time it initiates a new list so that your list gets emptied/a new list is defined.
Initialize the list outside while loop.
The list is reinitialized everytime therefore holds only the current iteration value.
Your break statement breaks the loop the first iteration through and your list gets redefined to be empty each iteration. The list should be outside the loop and the loop should only be broken when a certain criteria is met, otherwise it's an infinite loop. This can be accomplished with an if (criteria): break or while (criteria to be met, not yet met):
lista=[]
while True:
somenumber=randrange(5,20)
lista.append(somenumber)
if (some selection statement):
break
Another way to write it, for example if you want 25 items in your list, would be:
lista=[]
while len(lista)<25:
somenumber=randrange(5,20)
lista.append(somenumber)
Try this:
condition = 0 #start
limit = 10 #finish
lista=[]
while condition < limit: #while not yet reached finish
somenumber=randrange(5,20)
lista.append(somenumber)
condition += 1
Thanks guys. I think I know what to do. The game I am doing is an old game from C64, not sure if it was anywhere outside of Poland and in Poland it's title was "Namiestnik" - a text strategy where you were running Roman Colony

How to run a for loop with variable range?

I want to have a Python program like--
for i in range(r):
if (i==2):
#change r in some way
which will run the loop for the new range r, after it gets modified in the if statement.
Even if I change r after the if statement,the for loop runs for the initial r I gave.This must be happening because range(r) gets fixed in the for statement in the first line itself,and is not affected by change in r later on.
Is there a "simple way" to bypass this?
By "simple" I mean that I don't want to add a counter which counts how many times the loop already ran and how many times it need to run again after changing(specifically increasing) r,or by replacing for loop with a while loop.
When you say:
for i in range(r):
range(r) creates a range object. It does this only once when the loop is set up initially. Therefore, any changes you make to r inside the loop have no effect on the performance of the loop, since it's the range object that dictates the number of iterations (it just happens to be initialized with r).
Rule of thumb: If you know how many iterations you need in advance, use a for loop. If you don't know how many iterations you need, use a while loop.
I don't believe this is possible. However, using a while loop and a manual counter is itself an extremely simple way to do this.
The code will look something like this:
i = 0
while i < r:
if i == 2:
# Change r in some way

Is there a conditional that runs if an if statement does not activate within a loop?

Making a simple program that swaps the location of numbers in a loop until they are in ascending order. I want the program to end when the if conditional is never activated within a instance of the for loop. Is there a shorter way to do this without the use of a while true/false or like?
while tf == True:
for i in range(lisLen-1):
tf=False
if listy[i]>listy[i+1]:
tf=True
swap(listy, i, i+1)
Get rid of the variable, and use break instead. Then you can use the else: clause to test this. That clause runs if the loop ended normally instead of with break.
while True:
for i in range(lisLen-1):
if listy[i]>listy[i+1]:
swap(listy, i, i+1)
break
else:
break

Python 3.6.2 not running loops over a single value

In my code I have implemented a loop where the lower and upper bounds are variable, and it can happen that lower and upper bound are the same. In this case, Python skips the loop.
for i in range(low_, high_):
print(i)
Is there a way to fix this in the definition of the loop?
yes, when low == high, the loop does not enter.
Loops run from start to the inclusion of (end - 1); it is therefore entirely normal behavior
In the case where low == high, you must test to print the low. (credits to #Michael_heath for catching a mistake in the comments)
for i in range(low_, high_):
print(i)
if low_ == high_:
print(low_)
Try running:
for i in range(low_, high_ + 1):
print(i)
It sounds like you want your loop to start at low_ and get to high_, even if they're the same. So adding the extra '+ 1' should get you what you want.
In general a loop only gets to one less than the second value. If you want to hit that value, adding the extra one should do the trick.

Categories