Search code examples
pythonlistascii

IndexError when iterating a list for Palidrome problem


Below is my solution for checking whether a string is a valid palidrome. The problem requires the removal or all non-alphanumeric characters, and the conversion of uppercase letters into lowercase, before checking whether what remains is a valid palidrome. I tried to tackle the problem using the ASCII table and Python's built in functions of ord() and chr().

def isPalindrome(s: str) -> bool:
        lst = list(s)
        for i in range(len(lst)):
            if ((ord(lst[i]) <= 122) and (ord(lst[i]) >= 97)) or ((ord(lst[i]) >= 48) and (ord(lst[i]) <= 57)):
                continue
            elif ord(lst[i]) >= 65 and ord(lst[i]) <= 90:
                lst[i] = chr(ord(lst[i]) + 32)
            else:
                lst.pop(i)
                
        for i in range(len(lst)):
            if lst[i] != lst[len(lst)-1-i]:
                return False
        
        return True

However, the program gives an IndexError, stating that the list index is out of range for the line

if ((ord(lst[i]) <= 122) and (ord(lst[i]) >= 97)) or ((ord(lst[i]) >= 48) and (ord(lst[i]) <= 57)):

I don't see why this would be the case? I am iterating through the length of the list no?


Solution

  • it's a common problem: it's due to pop. You are going to short your list after computed the size, that is bigger at the beginning. In the following solution, you are creating a new list based on the ordinals of the first one, removing special chars and making all letters lower before performing the check:

    python
    def remove_special(s: str) -> list:
            lst = list(s)
            copy = list()
            for i in range(len(lst)):
                if ((ord(lst[i]) <= 122) and (ord(lst[i]) >= 97)) or ((ord(lst[i]) >= 48) and (ord(lst[i]) <= 57)):
                    copy.append(ord(lst[i]))
                elif ord(lst[i]) >= 65 and ord(lst[i]) <= 90:
                    copy.append(ord(lst[i]) + 32)
                else:
                    continue
            return copy
    
    
    def isPalindrome(s: str) -> bool:
            lst = remove_special(s)                
            for i in range(len(lst)):
                if lst[i] != lst[len(lst)-1-i]:
                    return False
            
            return True