Anagram function returns False for unknown reason in some words – Python

Question:

I’ve tried to create a function that returns True if two words are anagrams (have the same letters) to each other.

I realized that my counter counts to 13 but not sure what is the issue.

def is_anagram (worda: str , wordb: str) -> bool:
    count_same_letters = 0
    if len(worda) == len(wordb):
        for i in worda:
            for j in wordb:
                if i == j:
                    count_same_letters = count_same_letters+1
                    print(count_same_letters)
                    print(len(wordb))
        return count_same_letters == len(wordb)
    else:
        return False

print(is_anagram("anagram","nagaram"))

while trying the string ‘abc’ abd ‘bca’ the output was True as I expected, but the strings ‘anagram’ and ‘nagaram’returns False

Asked By: Yael Chen

||

Answers:

The issue is that your code has counted the same letter multiple times. Try to run your code here – https://pythontutor.com/ and see each step-by-step the counts.

You could simplify it by using collections.Counter() in standard lib to make the faster counts and compare with each letters.


def is_anagram(str1, str2):
    a = str1.lower()        # if don't care case, can skip these steps
    b = str2.lower()
    
    return Counter(a) == Counter(b)



if __name__ == '__main__':
    string1 = 'funeral'
    string2 = 'realFun'

    print(is_anagram('anagram', 'nagaram'))   # True

    print(is_anagram(string1, string2))       # True
    print(is_anagram('abbac', 'cbbac'))       # False
Answered By: Daniel Hao

You are going through each pair of letters.

For instance if you have two 5-letter words, you’re going through 25 pairs of letters. If you input aaaab and baaaa, your count_same_letters counter will get to 4*4 + 1*1 (4*4 pairs of a‘s and 1*1 pairs of b‘s).

Change your algorithm.

Answered By: Arseny

As mentioned, the problem here is that letters occurring more than once are counted again. Supposing you need to implement the algorithm yourself without Count, here’s one approach to the problem:

def is_anagram (worda: str , wordb: str) -> bool:
    if len(worda) == len(wordb):
        remaining_letters = wordb
        for letter in worda:
            letter_index = remaining_letters.find(letter)
            if letter_index == -1:
                return False # no! not anagram
            
            remaining_letters = remaining_letters[:letter_index] + remaining_letters[letter_index+1:]
        
        if len(remaining_letters) == 0:
            return True
    else:
        return False
                
print(is_anagram("anagram", "gramnaa"))
print(is_anagram("omg", "omggg"))
print(is_anagram("abc", "cba"))
print(is_anagram("aaaa", "aaaaaa"))  

By "deleting" every letter we find from remaining_letters our code will have to search through a smaller string on each iteration, possibly making it perform faster then some other alternatives.

Answered By: Kepedizer
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.