10
\$\begingroup\$

I see a couple of these on codereview but I was hoping my way hasn't yet been encountered:

def is_palindrome_permutation(strng):
    cache = set()
    for char in strng.lower():
        if not char.isalpha():
            continue
        if char in cache:
            cache.remove(char)
        else:
            cache.add(char)

    return len(cache) <= 1

Instead of maintaining any counts of characters to check for oddness or evenness, simply add and remove characters from a set. A character repeated an even number of times will be removed from the set; a character repeated an odd number of times will remain in the set. If the final set has a length less than or equal to one, it is a permutation of a palindrome.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ I would call the function is_anagram_of_palindrome. Does it handle utf-8 or just a..z? You might want to state in a comment what you consider legal characters. \$\endgroup\$
    – Bent
    Commented Oct 22, 2016 at 18:08

2 Answers 2

15
\$\begingroup\$

Documentation

You should definitely add a docstring. It took me a few seconds to figure out was was going. Make sure to add some examples in the docstring as well.

Naming

The name cache may not be the best name. Why? Let's look at the definition of cache:

is a hardware or software component that stores data so future requests for that data can be served faster

I don't really believe you use cache to serve stuff faster. I believe odd_occuring_letters is a better idea. (I don't like long names, maybe challenge yourself to a shorter name? Maybe odd_letters? Think about it.)

(More) Comments

Even then, odd_occuring_letters isn't the most descriptive name, so you should include some comments as to what your code does. Don't over do it though.

Remember saying something like:

# Check the length of odd_occuring_letters is less than or equal to one.
return len(odd_occuring_letters) <= 1 

Is not good. But saying:

# A word can have at most 1 odd character and still be palindrome.
return len(odd_occuring_letters) <= 1

explains to me why you return the length compared to one.

\$\endgroup\$
6
\$\begingroup\$

You can take advantage of the set.symmetric_difference_update() operation, which does exactly your conditional add/remove.

def is_palindrome_permutation(s):
    unpaired_chars = set()
    for char in s.lower():
        if char.isalpha():
            unpaired_chars ^= set(char)
    return len(unpaired_chars) <= 1
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.