How do you group a list of strings into groups of anagrams?
Give every word a canonical key that is the same for all its anagrams, then use that key to bucket the words in a dictionary. The simplest canonical key is the word with its characters sorted, because sorting produces the same sequence for any two words that contain the same characters.
from collections import defaultdict
def group_anagrams(words):
groups = defaultdict(list)
for word in words:
key = "".join(sorted(word))
groups[key].append(word)
return list(groups.values())
print(group_anagrams(["eat", "tea", "tan", "ate", "nat", "bat"]))The output is three groups: eat, tea and ate together, tan and nat together, and bat on its own. The key for the first group is aet, for the second ant and for the third abt, and the dictionary groups by that key.
The mechanism is that the key must be identical exactly when the words are anagrams, so the dictionary does the grouping for you. The cost is dominated by sorting each word, which is O of m log m for a word of length m, so the whole pass is O of n times m log m for n words of length m. Using a frequency tuple as the key instead makes each key O of m to build and O of m to hash, which is linear overall and is the version to prefer when the words are long.
The trade-off to name is space. You store every word plus its key, so the algorithm is linear in the total input size, and the sorted keys can be several times larger than the words themselves. If you only need to detect whether any two words are anagrams, you can hash the keys into a set and compare hashes, which uses less memory but loses the grouping. And in practice the first two words in a group are usually enough to know the group exists, so streaming with early exit is possible.