def checkPalindrome(self,lst):
return lst[:] == lst[::-1]
This is an extremely expensive implementation. lst[:]
is needlessly creating a copy of lst
, then lst[::-1]
creates a second complete copy of lst
(but reversed). There are many ways of approaching this, but I would go for something like this:
def checkPalindrome(self, lst):
return all(start == end
for start, end in zip(lst, reversed(lst)))
It zip
s lst
with a reversed
list iterator:
>>> lst = "abcd"
>>> list(zip(lst, reversed(lst)))
[('a', 'd'), ('b', 'c'), ('c', 'b'), ('d', 'a')]
Then checks to see if all
the pairs are equal. If they are, the list is a palindrome. This method is still inefficient though since only half of each needs to be checked. It can be further improved by introducing itertools.islice
to get a "view" of the first half of the zipped lists:
from itertools import islice
def checkPalindrome(self, lst):
half_pair_view = islice(zip(lst, reversed(lst)), len(lst) // 2 + 1)
return all(start == end for start, end in half_pair_view)
islice
is like normal list slicing except instead of creating a copy, it just allows you to iterate over a limited portion of the original iterable.
This code is more efficient because every function involved here is "lazy": they do only as much work as they need to. reversed
, zip
, islice
, and the generator expression all return an iterator that can produce elements (but do little work up front). all
also exits as soon as it gets a Falsey result, so it's comparable to a for
loop that contains a break
in some branches. This is key here because we only want to do as much work as is necessary to determine whether not they're palindromes. Making two full copies of the list does a large amount of work; far more than is required to check if the string is a palindrome.
checkOddChars
is a textbook use-case for a list comprehension:
def checkOddChars(self, lst):
return [i for i in lst if lst.count(i) == 1]
If you ever find yourself initializing an empty list, then iterating over another iterable and adding to the list, you likely want a comprehension.
This is quite an expensive function too. count
needs to iterate the entire list each time; once for every element in lst
. This also double counts any repeated elements. I'm not sure off the top of my head what a better solution is though.
del lst[0]
This is also quite expensive. Ideally, you shouldn't delete from a list except for at the very end. Lists don't support efficient deletes, and the closer to the beginning of the list you delete from, the worse it is. I'd switch to using a dequeue
instead of a list, which avoids the overhead of popping from the beginning.