57

I'm trying to check for a palindrome with Python. The code I have is very for-loop intensive.

And it seems to me the biggest mistake people do when going from C to Python is trying to implement C logic using Python, which makes things run slowly, and it's just not making the most of the language.

I see on this website. Search for "C-style for", that Python doesn't have C-style for loops. Might be outdated, but I interpret it to mean Python has its own methods for this.

I've tried looking around, I can't find much up to date (Python 3) advice for this. How can I solve a palindrome challenge in Python, without using the for loop?

I've done this in C in class, but I want to do it in Python, on a personal basis. The problem is from the Euler Project, great site By the way,.

def isPalindrome(n):
    lst = [int(n) for n in str(n)]
    l=len(lst)
    if l==0 || l==1:
        return True
    elif len(lst)%2==0:
        for k in range (l)
        #####
    else:
        while (k<=((l-1)/2)):
            if (list[]):
                #####   

for i in range (999, 100, -1):
    for j in range (999,100, -1):
        if isPalindrome(i*j):
            print(i*j)
            break

I'm missing a lot of code here. The five hashes are just reminders for myself.

Concrete questions:

  1. In C, I would make a for loop comparing index 0 to index max, and then index 0+1 with max-1, until something something. How to best do this in Python?

  2. My for loop (in in range (999, 100, -1), is this a bad way to do it in Python?

  3. Does anybody have any good advice, or good websites, or resources for people in my position? I'm not a programmer, I don't aspire to be one, I just want to learn enough so that when I write my bachelor's degree thesis (electrical engineering), I don't have to simultaneously LEARN an applicable programming language while trying to obtain good results in the project. "How to go from basic C to great application of Python", that sort of thing.

  4. Any specific bits of code to make a great solution to this problem would also be appreciated, I need to learn good algorithms.. I am envisioning 3 situations. If the value is zero or single digit, if it is of odd length, and if it is of even length. I was planning to write for loops...

PS: The problem is: Find the highest value product of two 3 digit integers that is also a palindrome.

Óscar López
  • 232,561
  • 37
  • 312
  • 386
DrOnline
  • 741
  • 1
  • 7
  • 9
  • 1
    Related: http://stackoverflow.com/a/7460573/846892 – Ashwini Chaudhary Jun 26 '13 at 22:10
  • 2
    I believe this is ProjectEuler #4. You should be able to find some solutions out there that could introduce you to python. But from the looks of it, your implementation is not a terrible one. Your `isPalindrome` can be much simpler. You may also want to store all palindromes you find in a list and then sort it to find the highest value. If you just `break`, you are not guaranteed the highest value palindrome. – wflynny Jun 26 '13 at 22:10
  • 1
    All these answers are good, although bear in mind that, as stated, your word/phrase has to be an *exact* palindrome for them to work, including capitalization, spaces, and punctuation. You'll want to look at methods like `.lower()` and `.translate()` to make the case uniform and remove the spaces and punctuation if you want to match cases like "Do geese see God?" – Crowman Jun 26 '13 at 23:23
  • @PaulGriffiths Thank you, in this specific program I am dealing with numbers, but I have seen the .lower() and .upper() functions, .translate() I will look into. Thanks a lot! – DrOnline Jun 27 '13 at 01:31
  • Just to clarify for future visitors to this question. The C style of checking for palindrome would involve a for loop like the following: for(int i=0; i – Ghos3t Mar 10 '19 at 08:18

35 Answers35

207

A pythonic way to determine if a given value is a palindrome:

str(n) == str(n)[::-1]

Explanation:

  • We're checking if the string representation of n equals the reversed string representation of n
  • The [::-1] slice takes care of reversing the string
  • After that, we compare for equality using ==
Anm
  • 447
  • 4
  • 15
Óscar López
  • 232,561
  • 37
  • 312
  • 386
  • Wow.. can you explain to me what this means? How can that line contain the logic to compare the leftmost value with the rightmost..? – DrOnline Jun 26 '13 at 22:09
  • 8
    It doesn't. It simply check that the word is equal to itself reversed. An advantage of python is that it allows you to work at an higher level of abstraction leading to cleaner and more elegant solutions – mariosangiorgio Jun 26 '13 at 22:11
  • 1
    @DrOnline I updated my answer. This is the pythonic way to do write the solution, by manipulating the very flexible list data structure provided by the language – Óscar López Jun 26 '13 at 22:12
  • Thanks, but what does the :: mean, I thought that was like separation for the for loop arguments, such as for (int i = 0; i – DrOnline Jun 26 '13 at 22:13
  • 3
    @DrOnline the `::` part is called a _slice_, read all about it in [here](http://stackoverflow.com/a/509295/201359) – Óscar López Jun 26 '13 at 22:14
  • 17
    `[::-1]` is advanced slicing. `[a:b:c]` means slice from `a` (inclusive) to `b` (exclusive) with step size `c`. – wflynny Jun 26 '13 at 22:15
  • This slicing looks similar to that of `numpy`s version of slicing. However, I have seen that numpy has a better performance than vanilla python. Does this operation perform with similar speeds to a numpy array version of the same operation? – chase Feb 28 '16 at 22:54
  • this slice notation is equivilant to using slice() function but this looks much cleaner –  Sep 02 '19 at 08:04
32

An alternative to the rather unintuitive [::-1] syntax is this:

>>> test = "abcba"
>>> test == ''.join(reversed(test))
True

The reversed function returns a reversed sequence of the characters in test.

''.join() joins those characters together again with nothing in between.

RichieHindle
  • 272,464
  • 47
  • 358
  • 399
  • 3
    @RichieHindle: I find `''.join(reversed(test))` to be just as unintuitive as `[::-1]`. The _really_ intuitive behaviour would be if you could write `test == reversed(test)`. (I'm not the downvoter.) – Benjamin Hodgson Jun 26 '13 at 23:00
  • 6
    You could do `list(test) == list(reversed(test))`. – Rob Apr 15 '16 at 07:08
15

Just for the record, and for the ones looking for a more algorithmic way to validate if a given string is palindrome, two ways to achieve the same (using while and for loops):

def is_palindrome(word):

    letters = list(word)    
    is_palindrome = True
    i = 0

    while len(letters) > 0 and is_palindrome:       
        if letters[0] != letters[(len(letters) - 1)]:
            is_palindrome = False
        else:
            letters.pop(0)
            if len(letters) > 0:
                letters.pop((len(letters) - 1))

    return is_palindrome

And....the second one:

def is_palindrome(word):

    letters = list(word)
    is_palindrome = True

    for letter in letters:
        if letter == letters[-1]:
            letters.pop(-1)
        else:
            is_palindrome = False
            break

    return is_palindrome
Jorge E. Hernández
  • 2,800
  • 1
  • 26
  • 50
9

The awesome part of python is the things you can do with it. You don't have to use indexes for strings.

The following will work (using slices)

def palindrome(n):
    return n == n[::-1]

What it does is simply reverses n, and checks if they are equal. n[::-1] reverses n (the -1 means to decrement)

"2) My for loop (in in range (999, 100, -1), is this a bad way to do it in Python?"

Regarding the above, you want to use xrange instead of range (because range will create an actual list, while xrange is a fast generator)

My opinions on question 3

I learned C before Python, and I just read the docs, and played around with it using the console. (and by doing Project Euler problems as well :)

jh314
  • 27,144
  • 16
  • 62
  • 82
  • 1
    Note that `xrange` is only needed (and only exists) in Python 2. In Python 3, the regular `range` behaves much like `xrange` used to (with a few extra new features, like slicing to get a different `range` object added). – Blckknght Jun 26 '13 at 22:20
  • 1
    No problem! If you want to get some indexes, use `xrange`. If you want a list and manipulate that list for something else, use `range` – jh314 Jun 26 '13 at 22:21
  • Thanks Blckknght, I got errors for xrange, was wondering if I had to include a library or something. Good to know! Kinda like raw input and input was merged to input, I see that was a Python 3 change. – DrOnline Jun 26 '13 at 22:34
8

Below the code will print 0 if it is Palindrome else it will print -1

Optimized Code

word = "nepalapen"
is_palindrome = word.find(word[::-1])
print is_palindrome

Output: 0

word = "nepalapend"
is_palindrome = word.find(word[::-1])
print is_palindrome

Output: -1

Explaination:

when searching the string the value that is returned is the value of the location that the string starts at.

So when you do word.find(word[::-1]) it finds nepalapen at location 0 and [::-1] reverses nepalapen and it still is nepalapen at location 0 so 0 is returned.

Now when we search for nepalapend and then reverse nepalapend to dnepalapen it renders a FALSE statement nepalapend was reversed to dnepalapen causing the search to fail to find nepalapend resulting in a value of -1 which indicates string not found.


Another method print true if palindrome else print false

word = "nepalapen"
print(word[::-1]==word[::1])

output: TRUE

Community
  • 1
  • 1
Ganesh Pandey
  • 5,216
  • 1
  • 33
  • 39
4

There is also a functional way:

def is_palindrome(word):
  if len(word) == 1: return True
  if word[0] != word[-1]: return False
  return is_palindrome(word[1:-1])
Khozzy
  • 1,064
  • 4
  • 15
  • 29
  • 1
    This has a minor error: "mannam" will give `IndexError: string index out of range`, as the most inner call is on the null string (as will giving it a null string). `if len(word) <= 1: return True` solves this issue, although it will consider null strings as palindromes. – TemporalWolf Nov 15 '16 at 21:42
2

I know that this question was answered a while ago and i appologize for the intrusion. However,I was working on a way of doing this in python as well and i just thought that i would share the way that i did it in is as follows,

word = 'aibohphobia'

word_rev = reversed(word)

def is_palindrome(word):
    if list(word) == list(word_rev):
        print'True, it is a palindrome'
    else:
        print'False, this is''t a plindrome'

is_palindrome(word)
sanster9292
  • 1,146
  • 2
  • 9
  • 25
1

There is much easier way I just found. It's only 1 line.

is_palindrome = word.find(word[::-1])
1

The most pythonic way to do this is indeed using the slicing notation to reverse the string as mentioned already:

def is_palindrome(string: str) -> bool:
    return string == string[::-1]

In some other occasions though (like technical interviews), you may have to write a "proper" algorithm to find the palindrome. In this case, the following should do the trick:

def is_palindrome(string: str) -> bool:
    start = 0
    end = len(string) - 1
    
    while end >= start:
        if string[end] != string[start]:
            return False
        start += 1
        end -= 1
        
    return True
  • Set pointers to the start and end of the string
  • Iterate while end exceeds start
  • If the character in end and start indices don't match then this is not a palindrome, otherwise keep comparing
  • Increase start pointer by 1
  • Decrease end pointer by 1

Test Cases:

import unittest

class Test(unittest.TestCase):

    palindromes = ['a', 'aa', 'aba', '12321']
    non_palindromes = ['ab', 'aab', 'cacacc']
    def test_is_palindrome(self):
        for case in self.palindromes:
            self.assertTrue(is_palindrome(case))

        for case in self.non_palindromes:
            self.assertFalse(is_palindrome(case))


if __name__ == '__main__':
    unittest.main()
Giorgos Myrianthous
  • 36,235
  • 20
  • 134
  • 156
1

You could use this one-liner that returns a bool value:

str(x)==str(x)[::-1]

This works both for words and numbers thanks to the type casting...

0

Here a case insensitive function since all those solutions above are case sensitive.

def Palindrome(string): 

  return (string.upper() == string.upper()[::-1]) 

This function will return a boolean value.

Chaker
  • 1,197
  • 9
  • 22
  • 3
    In Python3.3+, use [`str.casefold`](https://docs.python.org/3/library/stdtypes.html#str.casefold) instead – Adam Smith Jan 27 '15 at 20:36
0

doing the Watterloo course for python, the same questions is raised as a "Lesseon" find the info here:

http://cscircles.cemc.uwaterloo.ca/13-lists/

being a novice i solved the problem the following way:

def isPalindrome(S):
    pali = True
    for i in range (0, len(S) // 2):
        if S[i] == S[(i * -1) - 1] and pali is True:
            pali = True
        else:
            pali = False
    print(pali)
    return pali

The function is called isPalindrome(S) and requires a string "S". The return value is by default TRUE, to have the initial check on the first if statement.

After that, the for loop runs half the string length to check if the character from string "S" at the position "i" is the same at from the front and from the back. If once this is not the case, the function stops, prints out FALSE and returns false.

Cheers.kg

bausi2k
  • 29
  • 4
0

If the string has an uppercase or non-alphabetic character then the function converts all characters to lowercase and removes all non-alphabetic characters using regex finally it applies palindrome check recursively:

import re

rules = [
    lambda s: any(x.isupper() for x in s),
    lambda s: not s.isalpha()
]


def is_palindrome(s):
    if any(rule(s) for rule in rules):
        s = re.sub(r'[^\w]', '', s).lower()
    if len(s) < 2:
        return True
    if s[0] != s[-1]:
        return False
    return is_palindrome(s[1:-1])


string = 'Are we not drawn onward, we few, drawn onward to new era?'

print(is_palindrome(string))

the output is True for the input above.

ufukomer
  • 1,021
  • 1
  • 14
  • 16
0

maybe you can try this one:

list=input('enter a string:')

if (list==list[::-1]):
    print ("It is a palindrome")
else:
   print("it is not palindrome")
priya
  • 11
  • Welcome to StackOverflow. Your answer appears to be similar to several others that have already been posted, including the accepted response. If you feel your answer is different, please edit it to add detail. – TomG Mar 21 '16 at 02:59
0

You are asking palindrome in python. palindrome can be performed on strings, numbers and lists. However, I just posted a simple code to check palindrome of a string.

# Palindrome of string
str=raw_input("Enter the string\n")
ln=len(str)
for i in range(ln/2) :
    if(str[ln-i-1]!=str[i]):
        break
if(i==(ln/2)-1):
    print "Palindrome"
else:
    print "Not Palindrome"
0

The real easy way to do that it is

word = str(raw_input(""))
is_palindrome = word.find(word[::-1])
if is_palindrome == 0:
    print True
else:
    print False

And if/else here just for fancy looks. The question about palindrome was on Amazon's interview for QA

0

Assuming a string 's'

palin = lambda s: s[:(len(s)/2 + (0 if len(s)%2==0 else 1)):1] == s[:len(s)/2-1:-1]  
# Test
palin('654456')  # True
palin('malma')   # False
palin('ab1ba')   # True
Chenna V
  • 10,185
  • 11
  • 77
  • 104
0
word = "<insert palindrome/string>"
reverse = word[::-1] 
is_palindrome = word.find(reverse)
print is_palindrome

This was a question in Udacity comp 101, chapter 1. Gives a 0 for palindrome gives a -1 for not. Its simple, and does not use loops.

hxalchemy
  • 366
  • 1
  • 10
0

I wrote this code:

word = input("enter: ")
word = ''.join(word.split())`
for x in range(len(word)):
if list(word)[x] == ((list(word)[len(word)-x-1])):
if x+1 == len(word):
print("its pali")

and it works. it gets the word, then removes the spaces and turns it into a list then it tests if the first letter is equal to the last and if the 2nd is equal to 2nd last and so on.

then the 'if x+1 == len(word)' means that since x starts at 0 it becomes 1 and then for every next .. blah blah blah it works so it works.

0
#compare 1st half with reversed second half
# i.e. 'abba' -> 'ab' == 'ba'[::-1]

def is_palindrome( s ):
   return True if len( s ) < 2 else s[ :len( s ) // 2 ] == s[ -( len( s ) // 2 ):][::-1]
lllll
  • 37
  • 1
  • 5
0

You can use Deques in python to check palindrome

def palindrome(a_string): ch_dequeu = Deque() for ch in a_string: ch_dequeu.add_rear(ch) still_ok = True while ch_dequeu.size() > 1 and still_ok: first = ch_dequeu.remove_front() last = ch_dequeu.remove_rear() if first != last: still_ok = False return still_ok

class Deque: def __init__(self): self.items = [] def is_empty(self): return self.items == [] def add_rear(self, item): self.items.insert(0, item) def add_front(self, item): self.items.append(item) def size(self): return len(self.items) def remove_front(self): return self.items.pop() def remove_rear(self): return self.items.pop(0)

Nabaz
  • 1
  • 1
0
import string

word = input('Please select a word to test \n')
word = word.lower()
num = len(word)

x = round((len(word)-1)/2)
#defines first half of string
first = word[:x]

#reverse second half of string
def reverse_odd(text):
    lst = []
    count = 1
    for i in range(x+1, len(text)):

        lst.append(text[len(text)-count])
        count += 1
    lst = ''.join(lst)
    return lst

#reverse second half of string
def reverse_even(text):
    lst = []
    count = 1
    for i in range(x, len(text)):
        lst.append(text[len(text)-count])
        count += 1
    lst = ''.join(lst)
    return lst


if reverse_odd(word) == first or reverse_even(word) == first:
    print(string.capwords(word), 'is a palindrome')
else:
    print(string.capwords(word), 'is not a palindrome')
0

the "algorithmic" way:

import math

def isPalindrome(inputString):
    if inputString == None:
        return False

    strLength = len(inputString)
    for i in range(math.floor(strLength)):
        if inputString[i] != inputString[strLength - 1 - i]:
            return False
    return True
sargeMonkey
  • 606
  • 1
  • 7
  • 23
0

There is another way by using functions, if you don't want to use reverse

#!/usr/bin/python

A = 'kayak'

def palin(A):

    i = 0
    while (i<=(A.__len__()-1)):
        if (A[A.__len__()-i-1] == A[i]):
            i +=1
        else:
         return False

if palin(A) == False:

    print("Not a Palindrome")

else :

    print ("Palindrome")
Deba G
  • 9
  • 1
0

It looks prettier with recursion!

def isPalindrome(x):
z = numToList(x)
length = math.floor(len(z) / 2)
if length < 2:
    if z[0] == z[-1]:
        return True
    else:
        return False
else:
    if z[0] == z[-1]:
        del z[0]
        del z[-1]
        return isPalindrome(z)
    else:
        return False
Harrada
  • 83
  • 2
  • 8
0
def is_palindrome(string):
   return string == ''.join([letter for letter in reversed(string)])
pushkin
  • 9,575
  • 15
  • 51
  • 95
Lily P
  • 11
0
print ["Not a palindrome","Is a palindrome"][s == ''.join([s[len(s)-i-1] for i in range(len(s))])]

This is the typical way of writing single line code

Tarun 007
  • 64
  • 5
0
def pali(str1):
    l=list(str1)
    l1=l[::-1]
    if l1==l:
        print("yess")
    else:
        print("noo")
str1="abc"
a=pali(str1)
print(a)
ravi tanwar
  • 598
  • 5
  • 16
0

I tried using this:

def palindrome_numer(num):
num_str = str(num)
str_list = list(num_str)
if str_list[0] == str_list[-1]:
    return True
return False

and it worked for a number but I don't know if a string

da coconut
  • 809
  • 2
  • 9
  • 11
0
def isPalin(checkWord):
    Hsize = len(lst)/2
    seed = 1
    palind=True
    while seed<Hsize+1:
        #print seed,lst[seed-1], lst [-(seed)]
        if(lst[seed-1] != lst [-seed]):
            palind = False
            break
        seed = seed+1
    return palind

lst = 'testset'
print lst, isPalin(lst)    
lst = 'testsest'
print lst, isPalin(lst) 

Output

testset True
testsest False
Its not blank
  • 3,055
  • 22
  • 37
0

Simple program to find and delete palindrome numbers.

list1 =  [12, 45, 98, 76,21, 89, 63,36,10]
list2 = list1.copy()
list3 = list1.copy()
for i in list1:
    for j in list2:
        tmp = str(j)
        if str(i) == tmp[::-1]:
           list3.remove(j)
    list2=list3.copy()
print ("final list",list3)
manjunath
  • 37
  • 4
0
def palindrome(s):
if str(s) == str(s)[::-1]:
    return True
else:
    return False
-1

Here is an example that takes a user's input and checks if the input is a palindrome:

name = input("Write your word here:  ")
input("Press <enter> to check if the word is a palindrome.")
if str(name) == str(name)[::-1]:
    print("True")
else:
    print("False")

However, there is no need to even set up the if/else statement. You can directly print the result of the logical comparison, as shown here:

name = input("Write your word here:  ")
input("Press <enter> to check if the word is a palindrome.")
print(str(name) == str(name)[::-1])
David Ferenczy Rogožan
  • 23,966
  • 9
  • 79
  • 68
alxxas
  • 1
  • 2
    Please explain your post. What does it do to help the questioneer? How should it be implemented? What is obvious to you may not be obvious to others. – Jens Aug 03 '14 at 22:09
-1
#!/usr/bin/python

str = raw_input("Enter a string ")
print "String entered above is %s" %str
strlist = [x for x in str ]
print "Strlist is %s" %strlist
strrev = list(reversed(strlist)) 
print "Strrev is %s" %strrev
if strlist == strrev :
   print "String is palindrome"
else :
   print "String is not palindrome"
Kenly
  • 24,317
  • 7
  • 44
  • 60
tkhanna
  • 1
  • 1
-1

it is very easy

#palindrome
a=raw_input("enter the word")
b=a[::-1]
if a==b:
 print("enter word is palindrome")
else:`enter code here`
 print("not a palindrome")

thanks

Community
  • 1
  • 1
  • this solution already offered, you read the question and jumped in without reading the available answers – msudder Jul 21 '17 at 18:20