Ojasa Mirai

Ojasa Mirai

Python

Loading...

Learning Level

🟢 Beginner🔵 Advanced
🎯 Why Data Structures Matter📋 Lists: Ordered Collections🔑 Dictionaries: Key-Value Pairs🎪 Sets: Unique Values & Speed📦 Tuples: Immutable Sequences⚖️ Comparing All Data Structures🔧 Mastering List Methods⚡ Advanced Dictionary Patterns🔄 Power of Set Operations🏗️ Building Nested Structures⚙️ Performance Tuning & Optimization
Python/Data Structures/Dictionary Advanced Patterns

🚀 Advanced Dictionary Patterns — Collections and Algorithms

Master specialized dictionary types and advanced patterns for complex data manipulation.


🎯 DefaultDict for Automatic Initialization

`defaultdict` eliminates the need for checking if keys exist before accessing.

from collections import defaultdict

# Traditional approach - verbose
graph = {}
for u, v in [(1, 2), (1, 3), (2, 3)]:
    if u not in graph:
        graph[u] = []
    graph[u].append(v)

# DefaultDict approach - cleaner
graph = defaultdict(list)
for u, v in [(1, 2), (1, 3), (2, 3)]:
    graph[u].append(v)

print(dict(graph))  # {1: [2, 3], 2: [3]}

# Different default factories
from collections import defaultdict

# Default to 0 (for counting)
counts = defaultdict(int)
for letter in "hello":
    counts[letter] += 1

# Default to empty set
groups = defaultdict(set)
groups["A"].add(1)
groups["A"].add(2)

# Default to empty list
categories = defaultdict(list)
categories["odd"].append(1)
categories["odd"].append(3)

# Custom default factory
def default_config():
    return {"enabled": True, "value": 0}

configs = defaultdict(default_config)
print(configs["new_key"])  # {"enabled": True, "value": 0}

💡 Counter for Frequency Analysis

`Counter` simplifies counting elements and finding most common items.

from collections import Counter

# Count elements
text = "hello world"
letter_counts = Counter(text)
print(letter_counts)
# Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, 'w': 1, 'r': 1, 'd': 1})

# Most common elements
print(letter_counts.most_common(3))
# [('l', 3), ('o', 2), ('h', 1)]

# Counter arithmetic
c1 = Counter("hello")      # {'h': 1, 'e': 1, 'l': 2, 'o': 1}
c2 = Counter("world")      # {'w': 1, 'o': 1, 'r': 1, 'l': 1, 'd': 1}

union = c1 | c2            # Max counts
intersection = c1 & c2     # Min counts
difference = c1 - c2       # Positive counts only

# Real-world: Finding top N items
logs = ["error", "warning", "error", "info", "error", "warning"]
severity_counts = Counter(logs)
top_2 = severity_counts.most_common(2)  # [('error', 3), ('warning', 2)]

🎨 Complex Data Processing Patterns

Pattern 1: Grouping with Aggregation

# Group transactions by user and sum amounts
transactions = [
    {"user": "alice", "amount": 100},
    {"user": "bob", "amount": 50},
    {"user": "alice", "amount": 75},
    {"user": "bob", "amount": 25}
]

# Traditional approach
result = {}
for tx in transactions:
    user = tx["user"]
    if user not in result:
        result[user] = 0
    result[user] += tx["amount"]

# With defaultdict
from collections import defaultdict
result = defaultdict(float)
for tx in transactions:
    result[tx["user"]] += tx["amount"]

print(dict(result))  # {"alice": 175, "bob": 75}

Pattern 2: Inverse Mapping

# Original: user_id -> user_name
users = {1: "Alice", 2: "Bob", 3: "Carol"}

# Create inverse: user_name -> user_id
inverse = {v: k for k, v in users.items()}
print(inverse)  # {"Alice": 1, "Bob": 2, "Carol": 3}

# For many-to-many mappings
from collections import defaultdict
permissions = {
    "admin": ["read", "write", "delete"],
    "user": ["read", "write"],
    "guest": ["read"]
}

# Reverse: permission -> list of roles
roles_with_permission = defaultdict(list)
for role, perms in permissions.items():
    for perm in perms:
        roles_with_permission[perm].append(role)

print(dict(roles_with_permission))
# {"read": ["admin", "user", "guest"], "write": ["admin", "user"], ...}

Pattern 3: Memoization Dictionary

# Cache function results
memo = {}

def fibonacci(n):
    if n in memo:
        return memo[n]

    if n <= 1:
        result = n
    else:
        result = fibonacci(n-1) + fibonacci(n-2)

    memo[n] = result
    return result

# With decorator
from functools import lru_cache

@lru_cache(maxsize=128)
def fibonacci_cached(n):
    if n <= 1:
        return n
    return fibonacci_cached(n-1) + fibonacci_cached(n-2)

# Test
print(fibonacci(35))  # Fast with memoization
print(fibonacci_cached(35))  # Fastest with decorator

📊 Performance Patterns

PatternTimeSpaceUse Case
defaultdict(list)O(1)O(n)Grouping
defaultdict(int)O(1)O(n)Counting
CounterO(n log n)*O(n)Frequency top-k
MemoizationO(1) lookupO(n)Recursive calls
Inverse mappingO(n)O(n)Bidirectional lookup

*for most_common(k) operation

🔑 Key Takeaways

  • ✅ `defaultdict` auto-initializes missing keys
  • ✅ `Counter` optimized for frequency analysis
  • ✅ Dictionary comprehensions for transformations
  • ✅ Memoization eliminates redundant calculations
  • ✅ Inverse mapping for bidirectional lookups

Ready to practice? Challenges | Quiz


Resources

Python Docs

Ojasa Mirai

Master AI-powered development skills through structured learning, real projects, and verified credentials. Whether you're upskilling your team or launching your career, we deliver the skills companies actually need.

Learn Deep • Build Real • Verify Skills • Launch Forward

Courses

PythonFastapiReactJSCloud

© 2026 Ojasa Mirai. All rights reserved.

TwitterGitHubLinkedIn