1

I'm very new to Python, and I'm going through some example projects I found online but I'm stuck on my palindrome checker at the moment.

Right now, my code takes a word as an input, splits it in half, saves each part into separate variables, makes both of the variables lists, and from there it SHOULD reverse the second list so I can compare it to the first, but from what I've gathered trying to fix it, it's only appending half of the selection to the new list.

For example, if I enter "racecar", it'll split it into "race" and "ecar" just fine, but then when I go to reverse "ecar" it only gives me back "['c', 'e']". (Also, if I switch the variables around to reverse the first half, I get the same error)

I've been trying to figure it out for quite a while now and I'm not making any progress so some help would be very much appreciated!

Ninja Edit: If there's an easier way to do this (which I'm sure there is) I'd love to know, but I still want to figure out what I've done wrong in the code I already have so I can try to learn from it

Here's my code so far:

print "Please enter a word you want to check is a palindrome"
input = raw_input('> ')

#Gets lengths of input
full_length = len(input)
split_length = len(input) / 2

#If word has an even length split like this
if full_length % 2 == 0:
    first_half = input[0: split_length]
    second_half = input[split_length:full_length]

#If word does not have even length split like this
else:
    first_half = input[0:split_length+1]
    second_half = input[split_length:full_length]

#Make both halves lists
first_half_list = list(first_half)
print first_half_list
second_half_list = list(second_half)
print second_half_list

# Reverse second half
rev_second_half = []


for x in second_half_list:
    current_letter = second_half_list[0]
    second_half_list.remove(second_half_list[0])
    rev_second_half.insert(0, current_letter)

print rev_second_half

"""
#Check to see if both lists are identical

#If they are identical
print "This word is a palindrome!"

#If they are not identical
print "This word is not a palindrome."
"""

And this is the output I get when I enter 'racecar':

racecar
['r','a','c','e']
['e','c','a','r']
['c', 'e']
Thorium
  • 191
  • 1
  • 14
  • 2
    The simplest way to check for a palindrome is `word==word[::-1]`. This returns true or false. Source: http://stackoverflow.com/a/29224834/3161440 – jkd Apr 09 '15 at 04:29

3 Answers3

3

There's a lot of unnecessary work going on. No need to convert to lists; the interpreter can manage this all for you. No need to manually reverse a string; use slicing. No need to manually declare the indices of the first and last characters in your string; the interpreter knows where they are. Here's a fixed version of the code; you can view a demo at IDE One:

input = 'racecar'

#Gets lengths of input
full_length = len(input)
split_length = len(input) / 2

#If word has an even length split like this
if full_length % 2 == 0:
    first_half = input[:split_length]
    second_half = input[split_length:]

#If word does not have even length split like this
else:
    first_half = input[:split_length+1]
    second_half = input[split_length:]

print first_half
print second_half

rev_second_half = second_half[::-1]

print rev_second_half

race
ecar
race

Notice the way that the second half is getting reversed, by using a slice with a negative iteration step? You can just do that once, to your source string, and compare the result to the original. Now you have a one line method to check if a string is a palindrome: input == input[::-1]

A bit more on slicing syntax (you might like to check out this question). input[::-1] is exactly the same as input[0:len(input):-1]. The colons separate the three arguments, which are start : end : step. The first two create a range which includes start and everything between it and end, but not end itself. Not specifying start or end causes the interpreter to assume you mean "use 0" and "use len", respectively. Not specifying step causes an assumption of 1. Using a negative step means "start at end and go backwards by magnitude of step".

If you want to omit arguments and specify a range with a slice, you need to include the colons, so the interpreter can tell which arguments are omitted. For example, input[-1] will return the last element of input, because no colons means you're specifying an index, and negative means "go backwards from the end", so print input[:-1] would yield "raceca" if your input was "racecar".

As for what was going wrong with your code, the problem is in your reversing loop.

for x in second_half_list:
    current_letter = second_half_list[0]
    second_half_list.remove(second_half_list[0])
    rev_second_half.insert(0, current_letter)

You're removing items from the list you're iterating through. Don't do that, it's a great way to cause problems; it's why you're only getting half the list in this case. There's also needless copying going on, though that won't cause incorrect results. Finally, you're not using your iterated variable at all, which is a sure sign of some sort of problem with your loop code. Here, if you fixed the list mutation but continued using second_half_list[0], you'd get that letter repeated len(second_half_list) times. If you really need to actually reverse a list, you can do it like this instead:

for x in second_half_list:
    rev_second_half.insert(0, x)

But you should only actually iterate the list if you need some sort of side effects during the iteration. For a pure reversal in python, you want this, which will perform better:

rev_second_half = [reversed(second_half_list)]
Community
  • 1
  • 1
Esoteric Screen Name
  • 6,082
  • 4
  • 29
  • 38
  • Thank you! I knew I was making it more complicated than it needed to be. The one thing that confused me a little was "[::-1]" because I don't remember learning anything about using two colons next to each other - Do you think you might be able to explain what's going on there, or at least tell me what to Google to find out? :) – Thorium Apr 09 '15 at 04:39
  • @Thorium I've added some additional information about slicing syntax, hopefully that clears things up for you. If not, let me know and I'll edit again. – Esoteric Screen Name Apr 09 '15 at 04:49
0

To reverse the string (not in place):

rev_second_half = second_half_list[::-1]

To extend: I'd suggest keeping the halves as strings, as you can then just compare them with:== and the above reversing technique also works on strings.

Patrick
  • 121
  • 2
  • 8
0

The reason you're only getting two values is you're mutating your list while you iterate on it -- you just shouldn't do this, if only because it's a pain to reason about. As an example:

In [34]: nums = range(5)  # [0, 1, 2, 3, 4]

In [35]: for num in nums:
   ....:    print "num", num
   ....:    print "nums", nums
   ....:    nums.remove(nums[0])
   ....:
num 0
nums [0, 1, 2, 3, 4]
num 2
nums [1, 2, 3, 4]
num 4
nums [2, 3, 4]

Notice that this only looped three times. The first time through, everything's dandy, but you remove the first element. However, Python's looping logic thinks it has to go to the second item -- but you removed the first item! Does that mean the second item now, or the second item when things started? For Python's internals, it means the second item now -- which is the third item when things started (i.e. the value 2). From there, stuff just snowballs.

The lesson here is don't mutate a list while you iterate on it. Just use the other means for reversing folks have mentioned here.

jwilner
  • 6,348
  • 6
  • 35
  • 47