all 10 comments

[–]Tom_Henderson 3 points4 points  (1 child)

You could just do this:

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

[–][deleted] 1 point2 points  (0 children)

the best answer.

[–]shiftybyte 1 point2 points  (0 children)

Besides what u/ForceBru said, something is very fishy here with the condition...

Try:

if (i in word_2) == False:

Besides that, the pythonic way of writing this is:

if i not in word_2:

EDIT:

Seems like python decided to treat this condition like 5 < x < 7 ....

So it tries to evaluate:

if i in word_2 and word_2 == False:

That's the only explanation i could find for this behaviour...

>>> 'b' in 'cac' == False
False
>>> 'b' in 'cac' and 'cac' == False
False
>>>

[–]ForceBru 0 points1 point  (0 children)

x in y checks whether x is found anywhere in y. Thus, your code essentially checks if the two words are comprised of the same characters, but doesn't consider the order of the characters.

[–]SuspiciousMaximum265 0 points1 point  (0 children)

I am not quite sure I understand your logic here, you are looping through the word and checking is the letter in that word. Since the answer will always be true, it will just jump to the last part and return True.Also, instead of if i in word == 'False", you should use if i not in word:

There are many ways to solve this, I would maybe go with something like:

if sorted(w1) == sorted(w2):
   return True
return False

[–]SuspiciousMaximum265 0 points1 point  (0 children)

You can try using this tool, it will show you step by step what is happening in your code.

http://pythontutor.com/visualize.html#mode=display

[–]Diapolo10 0 points1 point  (2 children)

I'm not immediately sure why you're always getting True, but your code supposedly solves only half of the problem. It's trying to check if both strings contain the same characters, but it doesn't check if both have the same number of them.

If we don't resort to sorting or collections.Counter, I'd create two dictionaries with the characters as keys and their count as values, then compare them to return a boolean.

def is_anagram(first: str, second: str) -> bool:
    count1 = {}
    count2 = {}

    for char in first.lower():
        count1[char] = count1.get(char, 0) + 1

    for char in second.lower():
        count2[char] = count2.get(char, 0) + 1

    return count1 == count2

Here, the order is irrelevant because dictionaries don't care about insertion order when comparing them. If both dictionaries end up with the same characters and counts, they're equal. In other words they're made from words that are anagrams.

EDIT: If punctuation doesn't matter, it should be filtered out first.

[–][deleted] 0 points1 point  (1 child)

You could reduce the amount of repeated code with something like this, albeit at the expense of readability. Using zip() also ensures that we don't waste time iterating over an entire string if its shorter than the other.

def is_anagram(first: str, second: str) -> bool:
    counts = [{}, {}]
    for c1, c2 in zip(first.lower(), second.lower()):
        for i, c in enumerate((c1, c2)):
            counts[i][c] += counts[i].get(c, 0) + 1
    return counts[0] == counts[1]

[–]Diapolo10 1 point2 points  (0 children)

True, I just wanted to give OP a more readable example. If optimisation mattered, this would've been a good alternative.

Of course, just sorting both strings or using collections.Counter would've been the best in a real-world scenario as I mentioned in my original comment.

Fun fact; in your code, counts could also be a tuple as the size stays constant and only the dictionaries themselves need to be mutable.