Finding anagrams with math

Here is a neat and beautiful (although perhaps not that useful) idea on connecting math and programming.

In mathematics there is a theorem called The fundamental theorem of arithmetic. This theorem can be stated in the followin way:

Every integer n greater than 1 is either a prime number or can be represented as the product of prime numbers and this representation is unique except for the order of the factors.

(that last part simply states that we don’t really care that you can write 30 as 2*3*5, 2*5*3, 3*2*5, 3*5*2, 5*2*3, 5*3*2).

To take the above example: 30 is not prime and can be represented as 2*3*5. 220 is not prime and can be represented by 2*2*5*11. And there are no other combination of primes that would produce the product 30 or 220.

How can we use this for profit? (profit not guaranteed)

If we map every character (let’s stick to the lowercase letters in the English alphabet) to a prime number:

letterToPrime = {
    'a': 2,
    'b': 3,
    'c': 5,
    'd': 7,
    'e': 11,
    'f': 13,
    'g': 17,
    'h': 19,
    'i': 23,
    'j': 29,
    'k': 31,
    'l': 37,
    'm': 41,
    'n': 43,
    'o': 47,
    'p': 53,
    'q': 59,
    'r': 61,
    's': 67,
    't': 71,
    'u': 73,
    'v': 79,
    'w': 83,
    'x': 89,
    'y': 97,
    'z': 101,
}

We can then write a function that maps and takes the product of all letters in the word (remembering to remove whitespace and lowercasing the words).

def isAnagram(word1, word2):
    w1product = reduce(lambda x,y: x * y, [letterToPrime[l] for l in word1.lower().replace(' ', '')])
    w2product = reduce(lambda x,y: x * y, [letterToPrime[l] for l in word2.lower().replace(' ', '')])
    return w1product == w2product

And with that little function we have a fully operational anagram tester and see that satan and santa are anagrams. Neat!