My Python code is only selecting half of a list's contents?

廉价感情. 提交于 2021-01-28 20:57:57

问题


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']

回答1:


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)]



回答2:


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.




回答3:


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.



来源:https://stackoverflow.com/questions/29529627/my-python-code-is-only-selecting-half-of-a-lists-contents

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!