Why does my loop continue as an infinite loop? - python

I have a bit of code and I'm having trouble understanding why the loop is an infinite loop even though I have an else condition which should end the loop.
def add1(*args):
total = 0
add = True
for num in args:
while add == True:
if num!=6:
total = total + num
else:
add = False
return total
add1(1,2,3,6,1)
My question is, I have an else statement that changes the add to 'False' hence the loop should stop but for some reason it doesn't.
However, if I make a slight alteration to the code as such, it stops:
def add1(*args):
total = 0
add = True
for num in args:
while add == True:
if num!=6:
total = total + num
break
else:
add = False
return total
add1(1,2,3,6,1)
basically, adding a break.
I don't understand how expert python coders actually interpret 'break' in their minds. I've read articles on break, but still can't seem to understand it quite as well.
I don't understand why the 'break' is needed and why the 'else' can't suffice.

When you enter the for loop, num gets the value 1 (the first value in args). Then you enter the while loop (since add is True). Now, because num does not equal 6, you enter the if block, so the else block does NOT executes. Then, you just return to the while loop, and the value of num doesn't change. Then, because num does not equal 6 (remember it didn't change, it is still 1), once again you enter the if block, and so on until you terminate the program.
When you add the break, you exit the closest loop, which in this case is the while loop, so the for loop continues, until num gets the value 6, and add becomes False. When that happens, the while loop never executes again.

def add1(*args):
total = 0
add = True
for num in args:
if add == True:
if num!=6:
total = total + num
else:
add = False
break #breaking the for loop for better performance only.
return total
add1(1,2,3,6,1)
this adds till 6 is not encountered. you are using while loop unnecessarily. you have to break the infinite loop by some condition and that condition is when num!=6. even your else part can break the infinite while loop, but according to me the while loop itself is unnecessary.

I believe the purpose of your code is to sum up elements in *args up to first occurrence of number 6. If that is the case, the while loop is redundant here. Changing the first code snippet:
def add1(*args):
total = 0
for num in args:
if num != 6:
total = total + num
else:
break
return total
add1(1, 2, 3, 6, 1)
What actually happens in your original code is that the num variable doesn't change in any way when iterating in while loop, so it never enters the else part, effectively getting stuck on the first input argument that is not 6, see below:
def add1(*args): # [1, 2, 3, 6, 1]
total = 0
add = True
for num in args: # first element is 1. num = 1
while add == True:
if num != 6: # num = 1 always
total = total + num
# adding break here gets out of the while loop on first iteration, changing num = 2
# and later to 3, 6...
else: # else is never reached
add = False
return total
add1(1, 2, 3, 6, 1)

You should change the below codes:
from
if num != 6:
to
if total != 6:

Related

Cannibal numbers with target incorrect return

I'm trying to write a function that, when given a list of numbers or string of numbers separated by commas as well as a target number, will find the number of numbers in that list that are equal to the target or can become the target.
Numbers can change by eating numbers that are smaller than or equal to them, after eating a number the larger number will have grown by 1 and the smaller number disappears.
The function checks all the numbers in the provided list so if you have [27,9,11,10,8] and your target is 12 then the function should return 3 because 11 can eat 10 to become 12, 10 can eat 9 and 8 to become 12, and 9 can eat 8 then it can now eat 10 and then 11 to become 12.
My issue is that when provided with something like [3,3,3,2,2,2,1,1,1] with target 4, my function returns the wrong value (value should be 9). For some reason my function does not recognise numbers that are equal as numbers that can be eaten even though in the if statement there is a ">=".
def cannibal(l, target):
try:
l = l.split(",")
l.sort(reverse = True)
l = list(map(int, l))
print (l)
except:
l.sort(reverse = True)
print (l)
finally:
eatingl = l[:]
count = 0
flag = True
for i in range(0,len(l)-1):
if l[i] > target:
print (l[i],"got skipped at",i)
continue
if l[i] == target:
print (l[i],"at",i,"got added")
count += 1
continue
if l[i] < target:
while flag:
if eatingl[i] < target and len(eatingl) == 1:
flag = False
break
if eatingl[i] == target:
(eatingl[i],"at",i,"got added")
count +=1
flag = False
break
for j in range(0,len(eatingl)):
if eatingl[i] == eatingl[j]:
continue
print (eatingl[i],eatingl[j])
if eatingl[i] >= eatingl[j]:
print (eatingl[i],"is eating",eatingl[j])
eatingl.remove(eatingl[j])
eatingl[i] += 1
break
if eatingl[i] > target:
flag = False
break
print (count)
return count
my function does not recognise numbers that are equal as numbers that can be eaten even though in the if statement there is a ">=".
There is only one >= in your code, and not far above it is this:
if eatingl[i] == eatingl[j]:
continue
This line stops a number from eating an equal number. Did you want this line to stop a number from eating itself? If so, you need the condition above to be if i == j: instead.
There are, however, a few other problems with your code:
Once you've found one number that can reach the target, you need to reset the list for the next number. You already have a line eatingl = l[:] which will do this, but it's outside the for i in ... loop. Move it inside.
Secondly, under the line if eatingl[i] == target: you have the following line.
(eatingl[i],"at",i,"got added")
This puts together a tuple with four items in it and then throws it away because nothing is done with it. I'm guessing you are missing a print here.
Thirdly, your variable flag is set to True before the for i in ... loop starts. As soon as this variable gets set to False, the while loop never gets entered again, so your program will never find any more than one cannibal number. Instead, move the line flag = True to immediately above the while loop.
Next, when a number gets eaten you remove it from the list eatingl. This doesn't cause a problem when j > i, but it does when j < i, because removing the number at index j will move the number at index i to index i - 1, after which you then increment the number at index i, which might be a different number.
Adding to or removing items from a list that you are iterating through often causes problems. Instead of removing the numbers it is simpler to replace them with a placeholder value such as 0, -1 or None. You would need to be sure that you don't attempt to eat a number that has already been eaten, and you can do this by checking that eatingl[j] isn't the placeholder just before checking whether eatingl[i] >= eatingl[j].
If your program gets to the end of the j loop without breaking out of it, then there aren't enough other numbers that eatingl[i] could eat to reach the target. In this situation you would want to break out of the while loop. The easiest way to do this is to add an else clause to the for loop:
else:
print("Could do no more for", eatingl[i])
flag = False
break
The else line in the above should line up with the for j in ... line. A for loop can have an else block, and the code in the else block runs if the code in the for loop did not break.
Finally, your i loop should be for i in range(0,len(l)): rather than for i in range(0,len(l)-1):. If you have a unique smallest number, as in your example 27,9,11,10,8 then this isn't a problem: a unique smallest number cannot eat any other numbers so skipping it doesn't do any harm. But in your example 3,3,3,2,2,2,1,1,1, where the smallest number is 1 and there are three of them, each of the 1s can eat the other two 1s and then a 2 to become a 4.
I made these changes to your code and it gave me the output I expected it to.

Python Loop Controls Exercise

I just started studying python on hyperskill for the past few weeks.
Here's the scenario:
Write a program that reads from the console integers (one in a line) until their sum is equal to 0. Immediately after that, it should display the sum of the squares of all the entered numbers.
It is guaranteed that at some point the sum of the entered numbers will be equal to 0. After that, reading is not necessary to continue.
In case the first integer equals to 0, also stop reading values from the input. Print out 0 instead of the sum of the squares.
For example, we are reading the numbers 1, -3, 5, -6, -10, 13. At this point, we have noticed that the sum of these numbers is 0 and output the sum of their squares, not paying attention to the fact that there are still unread values.
num = int()
listtrigbreak = []
listsquares = []
sumtrig = 0
sumsqua = 0
while sumtrig != 0: # until sum of trig is not 0,
num = int(input()) #accept numbers
if num == "0": # while first input is 0,
print(0) # print 0
break # and break the loop
listtrigbreak.append(num) # append num to listtrig
sumtrig += sum(listtrigbreak) # add sum of list to sumtrig
for x in listtrigbreak: # for each number in listtrigbreak
squared = x ** 2 # convert each to squares, save variable
listsquares.append(squared) # add squared to listsquq
sumsqua = sum(listsquares) # sum of squares in listsqua
else:
print(sumsqua)
I can't even get past the first while loop. Whenever I run it, it skips the entire while loop and heads over to this:
else:
print(sumsqua)
I've really had a hard time with boolean logic from the start. I need explanations.
As other comments already pointed out, the while loop is a bit tricky since you initially declare the variable to 0. You could use a boolean switch that controls the while loop, like so:
input_integers = []
stop = False
while not stop: # So while we should keep asking user input...
num = int(input())
input_integers.append(num)
if sum(input_integers) == 0 and len(input_integers) > 0:
print('done')
stop = True
Now add the other functionalities in it, and you're done.

While loop that's meant to be infinite freezes after first cycle

My goal is to make a program that prints onscreen all of the prime numbers it can find, however I have this issue where the while loop runs only once, instead of repeating forever.
def isPrime(num):
if num < 2:
return False
if num == 2:
return True
if num % 2 == 0:
return False
i = 3
while i * i <= num:
if num % i == 0:
return False
i += 2
x = 1
while True:
x += 1
if isPrime(x):
print (x)
I also have tried adding print("You can see this.") at the very end of the code, and it runs, but only once.
I'm sure it's a common mistake, since Python is very strict on indentation, but could you guys help me discover it? Thanks in advance.
You need to return True at the very end, after and outside the final loop. Otherwise the function ends without explicitly returning anything, so it implicitly returns None which is interpreted as false.
The i +=2 is indented too deep, the inner loop never quits.
It should read
while i * i <= num:
if num % i == 0:
return False
i += 2
Otherwise i never increases and the loop goes on and on and on.

getting a for loop to restart if a condition is satisfied

Is there a way to get a for loop to start again at any point within the loop? Say line has a length of three. If the if statement is satisfied and my index increments, I want everything to start checking again at the first value of line.
(Note this whole thing is part of a while True loop).
for line in library:
if message[index:index + len(line)-2] == line[2:]:
ans += line[0]
index += len(line)-2 + 1
I think you need another while True above the for loop.
For example, this is a continuous loop unless there is a break condition
x = [1, 2, 3, 4, 5, 6]
restart = True
while restart:
for i in x:
# add any exit condition!
# if foo == bar:
# restart = False
# break
if i == value: # add your message condition
break
You could replace x with library in your case and i with line. Then instead if i == 4 you add your break condition that resets the loop and if you do have an actual break condition, you set the restart flag to False
Another option would be using a loop counter like n = 2 and use while n < 2: and then set n += 1 whenever your condition mets or n = 0 whenever you want to reset.
If I'm reading it right you want to entirely restart the loop when you find a match. Easiest way to do this is by breaking out of the for loop as you stated you have a while loop above it which remains True and will restart the for loop:
for line in library:
if message[index:index + len(line)-2] == line[2:]:
ans += line[0]
index += len(line)-2 + 1
break

Square factorization in python 3?

Note - Go down to the edits if you want the more recent code, look here if you want to see the original question. I have made edits to the code, however, so mistakes in this code block may be outdated.
As a self-taught Python 3 programmer, I have been working on a way to simplify radical expressions. The one part of the program that does not work, however, is the square factorization. I have a function that detects square numbers, which works fine. The function that does not work is the following-
def sqfactorslist(num):
factors = []
counter = num // 2 + 1
while counter > 0:
if counter == 1:
factors.append(num) #if no square ints other than 1 square into num, append and finish.
while is_square(counter) == True and counter != 1: #If counter is a valid square integer, append it's square and subtract it from num.
if (counter ** 2) >= num:
factors.append(counter ** 2)
num -= counter ** 2
else: #Else, continue with a program.
break
if counter > 0:
counter -= 1 #If counter more than 0, subtract 1 from it
else:
break #If number is equal to or less than 0, break
return factors #If the input is 32, this should return 16 and 2.
It doesn't return anything other than an infinite loop. Anyone know whats wrong?
Edit 1 -- I have changed the program so that it runs, but now I have a stranger issue: If I input a square number as num, for example 16, I get a number larger than the input, e.x. 81, in the return list. I get no returned elements for a non-square number.
To make it run, I indented the first if statement after the end of the second while loop.
Edit 2 -- I have changed the program again, but I come up with another issue similar to the one above. After eliminating another mistake, where I squared numbers already shown to be square, found in the second while loop, the program now has a new problem - If I use a non-square integer, it returns an empty list, and if I use a square integer, like 16, it gives me an infinite loop. Current code shown below --
def findsqfactors(num):
factors = []
counter = num // 2 + 1
while counter > 0:
if counter == 1:
factors.append(num) #If no square ints other than 1 square into num, append then finish.
while is_square(counter) == True and counter != 1: #
if counter >= num:
factors.append(counter)
num -= counter
else:
break
if counter > 0:
counter -= 1
else:
break
return factors

Categories

Resources