How to do check for a palindrome in Python? - python

Hi I'm working on a python function isPalindrome(x) for integers of three digits that returns True if the hundreds digit equals the ones digit and false otherwise. I know that I have to use strings here and this is what I have:
def isPal(x):
if str(1) == str(3):
return "True"
else:
return "False"
the str(0) is the units place and str(2) is the hundreds place. All I'm getting is False? Thanks!

Array access is done with [], not (). Also if you are looking for hundreds and units, remember that arrays are 0 indexed, here is a shortened version of the code.
def is_pal(num):
return num[0] == num[2]
>>> is_pal('123')
False
>>> is_pal('323')
True
You might want to take in the number as a parameter and then convert it to a string:
def is_pal(num):
x = str(num)
return x[0] == x[2]
Note that you can simply just check if string is equal to it's reverse which works for any number of digits:
>>> x = '12321'
>>> x == x[::-1]
True

str(1) will create a string of the integer value 1. Which won't equal the string value of the integer value 3 - so it's always False.
You should return True and False, rather than strings of "True" and "False"...
This is what you're aiming for taking into account the above... (which works with any length)
def pal(num):
forward = str(num)
backward = ''.join(reversed(forward))
return forward == backward

Your problem is that str(1) == '1' and str(3) == '3'. You're also returning string values reading 'True' and 'False' instead of using the actual True and False values.
Let me propose a much simpler function for you:
def isPal(x):
s = str(x) # convert int to str
return s == s[::-1] # return True if s is equal to its reverse
s[::-1] creates a reverse of the string; e.g. 'foo'[::-1] == 'oof'. This works because of extended slice notation.

Not sure why people are sticking to the string idea when division and modulo will do:
def isPal(x):
return (x/100)%10 == x%10
if the number is no larger than 999 (3 digits as the OP stated) then it simplifies to
def isPal(x):
return x/100 == x%10

str() casts a value into a str. You want to access each character. You might want to benchmark a few different techniques.
>>> t1 = timeit.Timer(stmt="""\
... def isPal(x):
... return x//100 == x%10
... isPal(434)
... isPal(438)
... """)
>>> t2 = timeit.Timer(stmt="""\
... def isPal(x):
... return str(x)[0] == str(x)[2]
... isPal(434)
... isPal(438)
... """)
>>> print "%.2f usec/pass" % (1000000 * t1.timeit(number=100000)/100000)
0.97 usec/pass
>>> print "%.2f usec/pass" % (1000000 * t2.timeit(number=100000)/100000)
2.04 usec/pass
So, it looks like the mod technique works:
def isPal(x):
return x//100 == x%10

str(1) just gives you the string representation of the number 1:
>>> x = 357
>>> str(1)
'1'
What you want is the first index of the string representation of x.
>>> x = 357
>>> str(x) #string representation of x
'357'
>>> str(x)[0] #first index of that
'3'
>>> str(x)[2] #third index of that
'7'
>>> str(x)[0]==str(x)[2] #compare 1st and last
False
>>> x = 525
>>> str(x)[0]==str(x)[2] #compare 1st and last
True

you compare number 1 and 3, but you needt to compare index of input variable.
x = 1000
def isPal(x):
return str(x[-1]) == str(x[-3]):

It looks like you still need to study Python syntax
Here is a way to achieve what you need :
>>> def isPal(x):
... x_as_str = str(x)
... if len(x_as_str) != 3:
... raise Exception("{} is not of length 3".format(x))
... return x_as_str[0] == x_as_str[2]
...
>>> isPal(42)
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 4, in isPal
Exception: 42 is not of length 3
>>> isPal(420)
False
>>> isPal(424)
True

str(x) delivers the string value of whatever you pass to it, so in your case the string "1" or the string "3". But what you actually want is to access the 1st and 3rd digit of the given number. So, first you want to convert that number to string (e.g. with str(num)), and then you have to consider that indices in strings begin with 0, not with 1.
So working code culd e.g. look like this:
def isPal(x):
if str(x)[0] == str(x)[2]:
return 'true'
else:
return 'false'
Output:
> isPal(101)
true
> isPal (203)
false

A smaller solution for this would be:
def isPalindrome(x):
return str(x) == str(x)[::-1]
This will work for words and integer values.

def is_palindrome() :
a=(raw_input("enter the name : "))
b=a[::-1]
if b == a:
print " it is palindarome"
else:
print " it is not palindarome"
is_palindrome()

Related

Determining validity if sum divisible by 10

Outline:
Find out if id is acceptable. Acceptable parameters is the sum of the
digits for each part of the id. If each sum is evenly divisible by 10
then the function returns the string "Acceptable", otherwise it
returns the string "Unacceptable".
Example:
isValid('123-12-134') → 'Unacceptable'
isValid('550-55-055') → 'Acceptable'
isValid('123-55-055') → 'Unacceptable'
I've tried converting the entire string into an int, but get some differing results in determining divisible by 10.
My attempted code is:
def isValid(id) :
id=id.replace('-','0')
id=int(id)
if id % 10==0:
return "Valid"
else:
return "Invalid"
Thanks in advance!
You might as well return boolean variables and just compare the output to determine what to print:
def summation(item):
return sum([int(i) for i in item])
def isValid(id_) :
id_part = id_.split('-')
result = [summation(item) % 10 == 0 for item in id_part]
return all(result)
Essentially this loops through all the characters in the split string and determines their sum - 3 sums per provided id.
Then we convert the summed list to a boolean list using your condition of x%10 == 0.
Finally we look at all() the elements of this boolean list to determine if it all True or contains a False.
If all are True then the return of isValid(id_) is True else it is False.
Usage:
ids = ['123-12-134', '550-55-055', '123-55-055']
for id_ in ids:
validity = isValid(id_)
print("Acceptable") if validity else print("Unacceptable")
Output:
Unacceptable
Acceptable
Unacceptable
you mean like this?
sentence = "123-123-123"
a = sum(int(x) for x in sentence if x.isdigit())
Hope this code can help you.
Found on this answer
you mean like this?
sentence = "123-123-123"
a = sum(int(x) for x in sentence if x.isdigit())
return a % 10 == 0
Hope this code can help you.
Found on this answer
We want to short-circuit the 'Unacceptable'.
def isValid(ID):
s = 0
for x in ID:
if x.isdigit():
s += int(x)
else:
if s % 10 == 0:
s = 0
else:
return 'Unacceptable'
return 'Acceptable' if s%10 == 0 else 'Unacceptable'
The solution requires splitting the string into parts using hyphens as separators, which are tested to ensure that the sum of each part's characters is a multiple of 10. The test fails if any of the parts are not a multiple of ten, so each part must be greater than or equal to ten. If any part fails, the string fails, so, there is no need to continue testing if a failed part is found. Acceptable must be returned if the string passes, or Unacceptable if it fails.
This single function solution is easy to read:
def teststring(test):
for part in test.split('-'):
part_failed = int(part)<10
if not part_failed:
sum_chars = 0
for char in part:
sum_chars += int(char)
part_failed = ((sum_chars % 10) != 0)
if part_failed: break
return 'Acceptable' if not part_failed else 'Unacceptable'
This solution uses list comprehension in two functions:
def testpart_comprehended(part):
return ((int(part)>=10) and ((sum(int(char) for char in part) % 10) == 0))
def acceptable_comprehended(test):
return 'Acceptable' if all(testpart_comprehended(part) for part in test.split("-")) else 'Unacceptable'
This solution uses list comprehension in one function:
def all_comprehended(test):
return 'Acceptable' if all(((int(part)>=10) and ((sum(int(char) for char in part) % 10) == 0)) for part in test.split("-")) else 'Unacceptable'
These answers are all too understandable. Please use
isValid = lambda x: (any(sum(map(int, s)) % 10 for s in x.split('-'))
* 'un' + 'acceptable').title()
Unacceptable
for example
>>> isValid('123-123')
'Unacceptable'
>>> isValid('123-127')
'Unacceptable'
>>> isValid('127-127')
'Acceptable'

Produce all the digits in an integer for python except the last

I have this function which is to give me the last digit of the number passed. Is there a way to get all the digits except the last one?
def lastdigit(num):
out = num%10
return out
def all_digits_except_last(num):
if abs(num) < 10:
return None # view comment
out = num // 10
return out
This snippet of code integer divides the number by 10 to get all the digits of the number except the last one - then returns it. It also checks if the integer is only one digit - if that is the case it returns None.
However, you could argue that there is no need to check for a single digit as said below.
Try multiply:
def lastdigit(num):
return int(num*0.1)
print(lastdigit(12355))
Output:
1235
Why not just
def not_last(x):
return x // 10
Another approach:
>>> def digits(n):
if n==0: yield 0
while n>0:
yield n%10
n = n/10
>>> n = 123456
>>> all_digits_except_last = [d for d in digits(n)][1:]
>>> all_digits_except_last
[5, 4, 3, 2, 1]
you can use slicing for this.
like:-
def except_last_digit(num):
convert_to_str = str(num)
length_of_str = len(convert_to_str)
except_last_digit =
convert_to_str[0:length_of_str-1]
convert_to_int = int(except_last_digit)
return convert_to_int
Handling digits is better done by casting your integer to a string.
def firstdigits(num):
return str(num)[:-1]
firstdigits(121) # '12'

How do I write a recursive function that multiplies each character in a string by 2?

I'm trying to complete a recursive function which given a number, returns a string where the returned value has duplicate of each digit
Example: if 507, returns 550077
if the number is only 0 then just return 0
also if it is a negative number, return the negative sign only once
Example: -507 returns -550077
I haven't yet implemented anything to recognize a negative number, I was just trying to get my function to work first
so far I have:
def double(x):
if x == 0:
return x
else:
x = str(x)
return x[0]*2 + double(x[1: ])
print(double(527))
however this returns IndexError: string index out of range
I had it working by printing the result instead of returning the result, but the problem I am trying to solve strictly wants the result returned, not printed. What am I doing wrong?
This works recursively, fixes the x==0 termination error, checks whether a character is a digit before doubling, and returns the final answer as an int (instead of a str).
def double(x):
x = str(x)
if len(x) == 0:
return ''
else:
first_char = x[0]
# only double if it's an integer
if first_char in map(str, range(10)):
first_char *= 2
return int(first_char + str(double(x[1: ])))
print(double(-527))
>>> -552277
Something like this might work.
def double(x):
if x == 0:
return x
else:
x = str(x)
l=[]
for a in x:
if a == '-':
l.append(a)
else:
l.append(a*2)
return ''.join(l)

How to get number of decimal places

How would I do the following:
>>> num_decimal_places('3.2220')
3 # exclude zero-padding
>>> num_decimal_places('3.1')
1
>>> num_decimal_places('4')
0
I was thinking of doing:
len((str(number) if '.' in str(number) else str(number) + '.').rstrip('0').split('.')[-1])
Is there another, simpler way to do this?
You can use a regex to parse value, capture the decimal digits and count the length of the match, if any:
import re
def num_decimal_places(value):
m = re.match(r"^[0-9]*\.([1-9]([0-9]*[1-9])?)0*$", value)
return len(m.group(1)) if m is not None else 0
this is a bit less "raw" than splitting the string with multiple if else, not sure if simpler or more readable, though.
The best and the most Pythonic way to achieve this is:
import decimal
x = '56.001000'
x = x.rstrip('0') # returns '56.001'
x = decimal.Decimal(x) # returns Decimal('0.001')
x = x.as_tuple().exponent # returns -3
x = abs(x) #returns 3
Above code can be written in simpler way as:
>>> x = '56.001000'
>>> abs(decimal.Decimal(x.rstrip('0')).as_tuple().exponent)
3
Below is the list of used functions for more reference:
str.rstrip(): Return a copy of the string with trailing characters removed.
decimal.Decimal(): Construct a new Decimal object based from value.
x.as_tuple(): Returns a namedtuple of the format: DecimalTuple(sign=0, digits=(1,), exponent=-3)
abs(): Return the absolute value of a number.
You dont need regex, you can convert to float and convert back to string! this automatically will remove the zeroes :
>>> def convertor(s):
... try :
... int(s.rstrip('0').rstrip('.'))
... return 0
... except:
... return len(str(float(s)).split('.')[-1])
...
>>> convertor('4.0230')
3
>>> convertor('4.0')
0
>>> convertor('4')
0
you could also just try something like:
try:
return len(str(num).split('.')[1].rstrip('0'))
except
return 0
By string process:
Check . is present in number string or not.
If Not present then return 0.
If present the split number string by . and get second item from the split result.
Remove 0 from the right side.
Return len of item.
code:
>>> def dCount(no_str):
... if "." in no_str:
... return len(no_str.split(".")[1].rstrip("0"))
... else:
... return 0
...
>>> dCount("2")
0
>>> dCount("2.002")
3
>>> dCount("2.1230")
3
>>> dCount("2.01230")
4
>>>
import re
def f(s):
ls = s.split('.', 1)
if len(ls) == 2 and re.match(r'\d*$', ls[1]):
return len(ls[1].rstrip('0'))
return 0
assert f('12') == 0
assert f('12.') == 0
assert f('12.1') == 1
assert f('12.100006') == 6
assert f('12.1.3') == 0
assert f('12.1abc') == 0
assert f('12.100000') == 1
The Decimal type is perfect for this, you can implement num_decimal_places() as follows:
from decimal import Decimal
def num_decimal_places(value: str):
return -Decimal(value).normalize().as_tuple().exponent
It works as follows: Decimal(value) parses the string, including exponent notation, then .normalize() strips any trailing zeros from the internal representation. .as_tuple().exponent contains the number of decimal places the internally stored integer is shifted to the left, so negative numbers specify the number of places to the right of the decimal.
You could try using the Decimal function in python:
abs(Decimal(string_value).as_tuple().exponent)
as explained in
Easy way of finding decimal places

How can I return false if more than one number while ignoring "0"'s?

This is a function in a greater a program that solves a sudoku puzzle. At this point, I would like the function to return false if there is more then 1 occurrence of a number unless the number is zero. What do am I missing to achieve this?
L is a list of numbers
l =[1,0,0,2,3,0,0,8,0]
def alldifferent1D(l):
for i in range(len(l)):
if l.count(l[i])>1 and l[i] != 0: #does this do it?
return False
return True
Assuming the list is length 9, you can ignore the inefficiency of using count here (Using a helper datastructure - Counter etc probably takes longer than running .count() a few times). You can write the expression to say they are all different more naturally as:
def alldifferent1D(L):
return all(L.count(x) <= 1 for x in L if x != 0)
This also saves calling count() for all the 0's
>>> from collections import counter
>>> def all_different(xs):
... return len(set(Counter(filter(None, xs)).values()) - set([1])) == 0
Tests:
>>> all_different([])
True
>>> all_different([0,0,0])
True
>>> all_different([0,0,1,2,3])
True
>>> all_different([1])
True
>>> all_different([1,2])
True
>>> all_different([0,2,0,1,2,3])
False
>>> all_different([2,2])
False
>>> all_different([1,2,3,2,2,3])
False
So we can break this down into two problems:
Getting rid of the zeros, since we don't care about them.
Checking if there are any duplicate numbers.
Striping the zeros is easy enough:
filter(lambda a: a != 0, x)
And we can check for differences in a set (which has only one of each element) and a list
if len(x) == len(set(x)):
return True
return False
Making these into functions we have:
def remove_zeros(x):
return filter(lambda a: a != 0, x)
def duplicates(x):
if len(x) == len(set(x)):
return True
return False
def alldifferent1D(x):
return duplicates(remove_zeros(x))
One way to avoid searching for every entry in every position is to:
flags = (len(l)+1)*[False];
for cell in l:
if cell>0:
if flags[cell]:
return False
flags[cell] = True
return True
The flags list has a True at index k if the value k has been seen before in the list.
I'm sure you could speed this up with list comprehension and an all() or any() test, but this worked well enough for me.
PS: The first intro didn't survive my edit, but this is from a Sudoku solver I wrote years ago. (Python 2.4 or 2.5 iirc)

Categories