# Two Tools That Make Dicts Smarter
# Counter and defaultdict — from the collections module
# redhorndev.com

from collections import Counter, defaultdict

# ─────────────────────────────────────────────
# Counter — count occurrences automatically
# ─────────────────────────────────────────────

scores = [85, 74, 85, 91, 85, 74]
counts = Counter(scores)
print(counts)
# Counter({85: 3, 74: 2, 91: 1})

# works on strings
letters = Counter("redhorndev")
print(letters)
# Counter({'r': 2, 'e': 2, 'd': 2, 'h': 1, 'o': 1, 'n': 1, 'v': 1})

# works on any iterable
words = ["bull", "raven", "bull", "ghost", "bull", "raven"]
word_count = Counter(words)
print(word_count)
# Counter({'bull': 3, 'raven': 2, 'ghost': 1})

# ─────────────────────────────────────────────
# Counter — useful methods
# ─────────────────────────────────────────────

scores = [85, 74, 85, 91, 85, 74, 63]
counts = Counter(scores)

print(counts[85])               # 3   — occurrences of 85
print(counts[99])               # 0   — missing key → 0, not KeyError

print(counts.most_common(2))    # [(85, 3), (74, 2)] — top 2
print(counts.most_common())     # all, sorted by frequency

# Counter is a dict — all dict methods work
print(list(counts.keys()))      # [85, 74, 91, 63]
print(sum(counts.values()))     # 7 — total count

# ─────────────────────────────────────────────
# defaultdict(list) — group items
# ─────────────────────────────────────────────

squads = defaultdict(list)
assignments = [
    ("Alpha", "Raven"),
    ("Bravo", "Wolf"),
    ("Alpha", "Ghost"),
    ("Bravo", "Viper"),
    ("Alpha", "Bull")
]

for squad, soldier in assignments:
    squads[squad].append(soldier)   # no "if key exists" check needed

print(dict(squads))
# {'Alpha': ['Raven', 'Ghost', 'Bull'], 'Bravo': ['Wolf', 'Viper']}

# ─────────────────────────────────────────────
# defaultdict(int) — count without checking
# ─────────────────────────────────────────────

word_count = defaultdict(int)
words = ["bull", "raven", "bull", "ghost", "bull"]

for word in words:
    word_count[word] += 1   # starts at 0 automatically

print(dict(word_count))
# {'bull': 3, 'raven': 1, 'ghost': 1}

# ─────────────────────────────────────────────
# defaultdict(set) — unique values per key
# ─────────────────────────────────────────────

seen = defaultdict(set)
log = [("Alpha", "Raven"), ("Bravo", "Wolf"), ("Alpha", "Raven"), ("Alpha", "Ghost")]

for squad, soldier in log:
    seen[squad].add(soldier)    # duplicates ignored automatically

print(dict(seen))
# {'Alpha': {'Raven', 'Ghost'}, 'Bravo': {'Wolf'}}

# ─────────────────────────────────────────────
# Quick reference
# ─────────────────────────────────────────────

# from collections import Counter, defaultdict
#
# Counter(iterable)         — count occurrences
# counter[key]              — count for key (0 if missing)
# counter.most_common(n)    — top n as list of (value, count) tuples
#
# defaultdict(list)         — missing key → []
# defaultdict(int)          — missing key → 0
# defaultdict(set)          — missing key → set()
#
# Counter is a dict — all dict methods work
# wrap defaultdict in dict() for cleaner printing
