简体   繁体   中英

Can't figure out well why my function is returning True with anagrams

This is my function (says if 2 compared words are anagrams or not):

def are_anagrams(word1, word2):
    word1list = list(word1)
    word2list = list(word2)
    anagramfalse = False
    anagramtrue = True
    if (word1 == word2):
        return anagramfalse
    if (word1list.sort()) == (word2list.sort()):
        return anagramtrue
    else:
        return anagramfalse

So this function is returning

are_anagrams("lopped", "poodle")

as True , for some reason. Can't figure out why. It should be compared the sorted list of letters for each word and returning a False .

Solution? Mainly just want to know what's wrong.

sort does not do what you think. Observe:

>>> x = list('lopped')
>>> print(x.sort())
None

Since None == None is always True, the function always returns True.

Further, the code can be simplified:

def are_anagrams(word1, word2):
    return sorted(word1) == sorted(word2)

Sample runs:

>>> are_anagrams("lopped", "poodle")
False
>>> are_anagrams("lopped", "doppel")
True

Notes:

  1. Both sort and sorted operate on strings as well as lists. There is no need to convert to lists first.

  2. sorted(word1) == sorted(word2) evaluates to True or False. Consequentl, the if-then-else statement can be eliminated.

Extensions to phrases and mixed-case

Phrases can also be considered anagrams of each other. Also, for anagrams, case should generally be ignored. Thus:

def are_anagrams(word1, word2):
    return sorted(word1.lower().replace(' ', '')) == sorted(word2.lower().replace(' ', ''))

Thus:

>>> are_anagrams('Lopped', 'Ed Plop')
True

Rejecting the case of words being equal

If the words are the same, should they be considered anagrams? If not, then use:

     def are_anagrams(word1, word2):
        return (word1.lower() != word2.lower()) and sorted(word1.lower().replace(' ', '')) == sorted(word2.lower().replace(' ', ''))

Example:

>>> are_anagrams('Lopped', 'Lopped')
False
>>> are_anagrams('Lopped', 'Old Pep')
True

Here's the issue: wordlist.sort() will return None because it does the sorting in place comparing None to None will always evaluate to True and yield falsified results. You should be using sorted() which instead returns the newly sorted list and then perform the comparison:

def are_anagrams(word1, word2):
    word1list = list(word1)
    word2list = list(word2)
    anagramfalse = False
    anagramtrue = True
    if (word1 == word2):
        return anagramfalse
    if (sorted(word1list)) == (sorted(word2list)):
        return anagramtrue
    else:
        return anagramfalse

Apart from that, there are further things to note, first, no need to set explicit names for True and False ; just return them:

def are_anagrams(word1, word2):
    word1list = list(word1)
    word2list = list(word2)
    if (word1 == word2):
        return False
    if (sorted(word1list)) == (sorted(word2list)):
        return True
    else:
        return False

Second off, no need to cast the strings to lists with list , sorted will take care of that for you automatically by creating a list from the string, sorting it and then returning it:

def are_anagrams(word1, word2):
    if (word1 == word2):
        return False
    if (sorted(word1)) == (sorted(word2)):
        return True
    else:
        return False

Third off word1 == word2 won't really do much as a "quick check" to exit early; sorting is fast in general, you could drop that all together:

def are_anagrams(word1, word2):
    if (sorted(word1)) == (sorted(word2)):
        return True
    else:
        return False

For the final step to make this code as sortest as possible, look at Johns answer; he simply returns the result of comparing the sorted objects. No need to be explicit if your comparison will yield the right value for you. :-)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM