For loop in Python somehow exits early - python

I am really sorry for the vague title but I don't really know the specifics of what's happening with my code. I am currently learning Python and finding it interesting so far. I am practicing the concept of generator functions and wrote a little program that finds palindromes using a generator function.
Here is the code (Python 3.6, written in Spyder):
def ispalindrome(n):
#creates a list for storing the element of the number one by one
l=[]
#storing the digits
while n!=0:
l.append(n%10)
n=int(n/10)
#setting useful variables
i=len(l)-1
flag=False
#traversing the list and checking whether palindrome
for n in range(0,len(l)):
#this block is executed only if n is less than (len(l)-1)-n
if n<i-n:
#comparing elements
if l[n]==l[i-n]:
#flag is set to true everytime l[n] equals l[(len(l)-1)-n]
flag=True
else:
break
#if n>(len(l)-1)-n
else:
break
#returns the flag
return flag
#basic generator function that yields whenever ispalindrome() returns true
def palindromes(n=1111):
while True:
if ispalindrome(n): yield n
n+=1
#traversing through palindromes generator function
for n in palindromes():
if n>1131: break
print('{} is a palindrome'.format(n))
When ran I get this output:
1111 is a palindrome
1121 is a palindrome
1131 is a palindrome
Needless to say the output is completely wrong. I added a few prints in my code and tried to find out the issue and it looks like the program is exiting the for loop inside ispalindrome() function early. It is exiting the for-loop as soon as it encounters two digits and two ends which match, when this should not be the case. Is it because of the break keyword somehow?
I will greatly appreciate if someone can point out what am I doing wrong with this code and how should I approach this correct the issue. Thanks in advance!

I think your problem is that you've got the idea backwards.
With the current format of your code you should be assuming it IS a palindrome and breaking when you discover it is not.
Instead you are assuming it is not, then setting it to "it is" the first time you see equality. But then the next time you see inequality you merely break without setting it to false again.
If I were to code this I wouldn't bother with a flag, I would merely return "false" the moment an inequality was found.

Your logic isn't right.
By default, you think the number is not a palindrome (flag=False), and if you see a mirrored int, you set the flag to true (if l[n]==l[i-n]: flag=True).
You should do the contrary. You should set the flag to True by default, and if an item is not mirrored, return a flag to False.

As pointed out by the fellow users, my code was clearly logically in the wrong. I was never setting back flag variable to False whenever I was exiting from the for loop. So I took in account the suggestions made and changed my code.
Here is the code following my previous solution with a flag variable:
def ispalindrome(n):
#creates a list for storing the element of the number one by one
l=[]
#storing the digits
while n!=0:
l.append(n%10)
n=int(n/10)
#setting useful variables
i=len(l)-1
flag=False
#traversing the list and checking whether palindrome
for n in range(0,len(l)):
#this block is executed only if n is less than (len(l)-1)-n
if n<i-n:
#comparing elements
if l[n]==l[i-n]:
#flag is set to true everytime l[n] equals l[(len(l)-1)-n]
flag=True
else:
flag=False
break
#if n>(len(l)-1)-n
else:
break
#returns the flag
return flag
#basic generator function that yields whenever ispalindrome() returns true
def palindromes(n=1111):
while True:
if ispalindrome(n): yield n
n+=1
#traversing through palindromes generator function
for n in palindromes():
if n>2552: break
print('{} is a palindrome'.format(n))
And here is the one suggested by both Blusky and Fredman (more efficient than mine to say the least):
def ispalindrome(n):
#creates a list for storing the element of the number one by one
l=[]
#storing the digits
while n!=0:
l.append(n%10)
n=int(n/10)
#setting useful variables
i=len(l)-1
#traversing the list and checking whether palindrome
for n in range(0,len(l)):
#this block is executed only if n is less than (len(l)-1)-n
if n<i-n:
#comparing elements
if l[n]!=l[i-n]:
#flag is set to true everytime l[n] equals l[(len(l)-1)-n]
return False
#if n>(len(l)-1)-n
else:
break
#returns the flag
return True
#basic generator function that yields whenever ispalindrome() returns true
def palindromes(n=1111):
while True:
if ispalindrome(n): yield n
n+=1
#traversing through palindromes generator function
for n in palindromes():
if n>2552: break
print('{} is a palindrome'.format(n))
P.S: I am neither a professional s/w dev nor have I access to high quality courses or a mentor, that's why question boards like stackoverflow is useful for me. I know this is a dumb question and if I thoroughly checked my code again and again I might have realized the mistake, but I don't think it requires a downvote, does it?

Related

I wrote a code that would print the odd numbers or the even numbers in a list according to users choice. But the append not working inside the def

I created a code that takes a list from the user and then asks the user to choose from printing only the odd numbers or the even numbers. But whenever the user choice is taken, the execution freezes. Using keyboard interrupt, I find that the execution stopped in either the odd or even function. Please help !!!
here is the code:
from os import lstat
def odd(lst,oddlst):
for i in range(0,n):
while(lst[i]%2!=0):
oddlst.append(lst[i])
return oddlst
def even(lst,evenlst):
for i in range (0,n):
while(lst[i]%2==0):
evenlst.append(lst[i])
return evenlst
lst = []
oddlst = []
evenlst = []
n = int(input("enter number of elements \n"))
print("\nenter the elements \n")
for i in range(0,n):
num = int(input())
lst.append(num)
print(lst)
choice = input(" Do you want to print odd elements or even elements \n (odd/even)
\n")
if(choice=="odd"):
odd(lst,oddlst)
print(oddlst)
elif(choice=="even"):
even(lst,evenlst)
print(evenlst)
else:
print("invalid choice")
Perhaps you meant to use an if instead of a while in your odd and even functions.
The reason your execution "freezes", is that you run into an infinite loop.
In either while, the i-th element gets checked, then appended to a list. But the condition, against which you are checking, doesn't change, neither does the index i.
Changing your whiles to ifs should solve your problem.
Also, for a more elegant solution to your problem, have a look at:
https://docs.python.org/3/library/functions.html#filter
How to filter a list

Palindrome detection program not working properly

Basically, I'm trying to solve this Leetcode problem about detecting palindromes (numbers that can be read the same back and forth,) but it seems that my program detects -121 as a valid palindrome and that 10 is also a palindrome, even though for the former I have a conditional that explicitly automatically returns False for negative numbers, and that the other conditional I wrote such that it should detect 10 as not a palindrome. Can someone offer some insight to where I went wrong? Here's my code:
class Solution(object):
def isPalindrome(self, x):
"""
:type x: int
:rtype: bool
"""
L=[]
n=0
a=str(x)
if x < 0:
print("False")
else:
for z in a:
L.append(int(z))
while n < len(L):
b=(-1*n)-1
if L[n] == L[b] and n == (len(L)/2)-1:
return("True")
print("True")
break
elif L[n] == L[b]:
n = n+1
elif L[n] != L[b]:
return("False")
print("False")
break
else:
return("False")
print("False")
break
I'm just taking this directly from the box where you write the code in on Leetcode, so that explains the top stuff.
Hey, everyone! Thanks for helping me out. It seemed that changing the strings to Booleans did help out a lot, despite Leetcode accepting the strings anyways. I added in a caveat that automatically detects numbers of length one digit to be automatically true (as when it goes to else, the division rounds down and things get messy), and Leetcode accepted it! So, thank you all so much. Also, I'll make sure next time to make sure my code is indented properly.
It is possible to check numeric palindromes without converting to strings:
def numPalindrome(N):
left,right = N,0
while left>right:
left,digit = divmod(left,10)
if left and left == right: return True # odd size palindrome
right = right*10 + digit
return left and left == right # even size palindrome
This works by forming a left and right part and comparing them for equality. The right part is formed progressively using the last digit of the left part. If, at any point the two parts are equal, we have a palindrome.
Instead of print("True"), you can directly return True
Here is a simple Palindrome() function
x = 123131 # some number
str(x) == str(x)[::-1] # compare it with its reversed

My code works fine but every time the input is a prime number it keeps on printing "This is a prime number." over and over. How do I stop this?

My code is a PYTHON program that identifies if a number is prime or not. When I entered 45 however, it said that 45 was a prime, even though 45 isn't a prime number. Also, every time I run the program, it prints 'Sorry, the number you have entered is not prime.' or 'The number is indeed prime!' multiple times, instead of once. How do I make it print the output statements once and how can fix the program so that it says 45 IS NOT a prime number.
n = eval(input("Enter a number to find if that number is prime: "))
a = 2
while n > a:
if ((n % a) == 0) & (a != n):
print('Sorry, the number you have entered is not prime.')
break
else:
print('The number you have entered is indeed prime!')
Because you are printing it every time. If you want to break after finding/not finding the prime number, indent one more level for the break.
Also, this does not calculate prime numbers. It calculates if its even number.
Follow the solution here
Your code has some issues. To start with, you're never updating a, so you only ever check if the number n is even.
Once you fix that, you have two indentation problems. The first is that the break line needs to be inside the body of the if statement. Indent it more so that it's inside the if block.
The second indentation issue is more subtle. If you leave the else where it is, it will print out that the number is prime every time you test a potential factor that doesn't divide the number. That's both unhelpful (since it prints a lot) and wrong (since it says the number is prime even if it will later find a factor and say it's not prime). You can fix this by unindenting the else line so that it is lined up with the while statement. Using an else after a loop is an obscure bit of Python syntax. The body of the else only runs if the condition of the loop fails. It gets skipped if the loop exits due to a break statement.
Here's all of those necessary fixes together:
while n > a:
if ((n % a) == 0) & (a != n):
print('Sorry, the number you have entered is not prime.')
break # indent this line more!
a += 1 # increment a, so you don't keep checking 2 over and over
else: # unindent this line (and the next line too)
print('The number you have entered is indeed prime!')
There are some other things that could be improved in your code, though they aren't causing it to run incorrectly. I'd recommend using int instead of eval to parse your number, and I'd use the logical-and operator and instead of the bitwise-and operator & in the if statement (though actually you don't need either, since the a != n check is redundant, as the loop would have already ended if it was true).

Tough time understanding the below Python Script

I am new to coding and I am having a hard understanding the below code which prints all the prime numbers below 10.
N = 10
primes = []
for n in range(2,N+1):
for p in primes:
if n % p == 0: break
else:
primes.append(n)
print(primes)
My question is- what is the value of p during the first iteration? Isn't it 0? If so, n%p is always 0 right? Please help me understand.
A for..in loop over an empty list basically does nothing; it says "for each element in this list, do something", and since there is nothing in the list, it does nothing. So on the first iteration of the outer loop, the for p in primes does nothing at all, and the else clause is invoked.
On subsequent iterations there is something in primes, so the loop will get invoked and p will be populated with values.
The else clause of a for..in loop will be executed at the end of the loop, unless the loop is interrupted by break. That's exactly what is happening on your code: if the loop finds a divisible number, it breaks the loop and nothing happens, otherwise the number will get added to primes.
The algorithm in a nutshell is: for numbers from 2…10, if the number is not a multiple of an already discovered prime, it's a prime.

If .. else in python

I wrote a program in Python to generate prime numbers
here is the program
def genPrimes(n):
primes = [2] # primes generated so far
last = 3 # last number tried
while last <= n:
for p in primes:
if last % p == 0 and math.sqrt(p) <= last:
break
else:
primes.append(last)
last += 2
return primes
http://codepad.org/d33tsQyT
This program is producing a right answer. If you see the indentation for else: statement it is wrongly placed. if i try to place the else statement in if block interpreter is showing memory error. Can anyone tell why this is happening.
Thanks in advance
Maries
The else is actually attached to the for loop, and executes if the program doesn't break out of the loop. In your case, it executes if none of the primes divide into the number, so the number is prime and gets appended to the list.
See also the documentation.
It's not placed incorrectly, python is assuming you're using a for-else loop.
From the docs:
When used with a loop, the else clause has more in common with the
else clause of a try statement than it does that of if statements: a
try statement’s else clause runs when no exception occurs, and a
loop’s else clause runs when no break occurs.

Categories