DEV Community

Shahrouz Nikseresht
Shahrouz Nikseresht

Posted on

Day 50: Python Group Anagrams – The Cleanest O(n * m log m) Way to Cluster Words by Letter Signature

Welcome to Day 50 of the #80DaysOfChallenges journey! This intermediate challenge solves the classic group anagrams problem (LeetCode #49), where you take a list of words and return groups of all anagrams together. The solution uses a dictionary with sorted strings as keys, achieving perfect grouping with crystal-clear logic and excellent performance that's excellent in practice.

Example:

["eat","tea","tan","ate","nat","bat"] → [["eat","tea","ate"],["tan","nat"],["bat"]]

If you're preparing for interviews, working with text data, or just love elegant dictionary tricks, this "Python group anagrams" solution is the one recruiters love to see: readable, efficient, and Pythonic.


💡 Key Takeaways from Day 50: Anagram Grouping Function

This challenge delivers a defaultdict-based solution that normalizes each word into a canonical form (sorted characters) and uses it as a key. We'll break it down: function with defaultdict and sorted key, loop for grouping, and interactive main with input.

1. Function Design: Defaultdict for Automatic List Creation

def group_anagrams(words: list[str]) -> list[list[str]]:
    """
    Group words that are anagrams of each other.

    Uses a dictionary where the key is the sorted word
    (normalized form), and the value is a list of matching words.

    Returns a list of groups, each group containing anagram words.
    """
    groups = defaultdict(list)

    for word in words:
        key = "".join(sorted(word))  # normalized form
        groups[key].append(word)

    return list(groups.values())
Enter fullscreen mode Exit fullscreen mode

defaultdict(list) is the star: no need to check if key exists, it auto-creates empty lists.

key = "".join(sorted(word)) creates the perfect signature: "eat" and "tea" both become "aet".

Time: O(n * m log m) where m is max word length (sorting dominates).

Space: O(n) for storage.

2. The Core Logic: One Pass, Perfect Grouping

for word in words:
    key = "".join(sorted(word))  # "bat" → "abt"
    groups[key].append(word)
Enter fullscreen mode Exit fullscreen mode

Each word processed once. Same key = same group. Returns values() as list of lists, order by first appearance.

3. Main Interactive: Real Input Testing

print("Enter words separated by spaces:")
input_words = input("> ").strip().split()

if not input_words:
    print("No words entered. Exiting.")
else:
    grouped = group_anagrams(input_words)
    print("\nGrouped anagrams:")
    for group in grouped:
        print(group)
Enter fullscreen mode Exit fullscreen mode

Clean input handling, immediate visual feedback. Try "cat act tac dog god" → [['cat', 'act', 'tac'], ['dog', 'god']]


🎯 Summary and Reflections

This anagram grouper is elegant, readable, and production-ready. It reinforced:

  • Normalization is key: Sorted string as signature, perfect for anagrams.
  • defaultdict magic: Eliminates "if key in dict" boilerplate.
  • One-pass efficiency: No sorting the final groups needed.

This exact pattern appears constantly in text processing, log analysis, and search engines.

Advanced Alternatives:

  • Use tuple(sorted(word)) as key (faster lookup, no join)
  • Counter(word) as key: from collections import Counter; groups[Counter(word)]
  • For huge datasets, use frozen Counter as key

But for 99% of cases, this sorted-string version is unbeatable for clarity.


🚀 Next Steps and Resources

Day 50/80! We're halfway through the journey and getting seriously strong!

What's your favorite dictionary trick? Drop it in the comments! 🔥

Top comments (0)