Skip to content
Lesson 5 of 12

Step 1 of 7 · Reading · ~4 min

Learn

Dictionaries and Sets

Dictionary Techniques

By the end of this lesson you can count and group with Counter and defaultdict, merge dictionaries knowing which side wins, and spot the places where these tools quietly do something you did not ask for.

The d[k] = d.get(k, 0) + 1 loop from Dictionary Fundamentals is the manual version of counting. The standard library packages that loop, and the grouping loop that goes with it.

Counter: a dict that counts

collections.Counter is a dict subclass. Give it any iterable and it counts the items:

python

A missing key reads as 0 and is not inserted, so c[k] += n works on the first sight of a key, and n can be negative. most_common(n) returns the n biggest (key, count) pairs. Equal counts come out in first-seen order:

python

Print dict(c) or loop over c.items(), not the raw Counter.

Counter + keeps only positives

+ adds counts per key and then drops every key whose total is zero or negative. update adds the same way but keeps what it computes:

python

When counts can be zero or negative (refunds, stock sent out), accumulate with c[k] += n, never with + or sum() of Counters.

defaultdict: a dict that builds missing values

defaultdict(factory) calls factory() with no arguments when you read a key it lacks, stores the result under that key, and returns it. list and int (int() is 0) are the usual factories:

python

Any class callable with no arguments works as the factory, so defaultdict(Counter) gives each key its own Counter and table[a][b] += 1 counts in two levels.

The trap: a plain read inserts. get and in do not:

python

An if d[k]: meant as a question has just added k.

setdefault, merging, inverting

On a plain dict, d.setdefault(k, v) returns d[k] if present, otherwise stores v and returns it, so groups.setdefault(team, []).append(ticket_id) is the grouping loop without an import.

python

{**a, **b} builds a new dict and the later one wins a clash; a.update(b) does it in place. The a | b operator is Python 3.9 and raises TypeError on the 3.8 grader. A merge replaces values, it does not add them: to add, merge Counters.

Inverting collides the same way. {v: k for k, v in s.items()} on {"ann": "ops", "bo": "web", "cy": "ops"} gives {'ops': 'cy', 'web': 'bo'} and ann is lost. Group instead (inv[v].append(k) on a defaultdict(list)) to keep everyone.

Common mistakes

  • Combining Counters with + or sum() when counts can be zero or negative. A key totalling 0 vanishes, and if every total is non-positive the result is empty, so most_common(1)[0] raises IndexError.
  • Probing a defaultdict with d[k]. The key is inserted, so a later len(d) counts keys that were only asked about.
  • dict.fromkeys(keys, []) stores one list under every key: after f["a"].append(1), f is {'a': [1], 'b': [1]}, the aliasing from List Basics. Use {k: [] for k in keys}.

Your exercise

Summarise a warehouse movement log where quantities can be negative: per-warehouse figures, then the top item overall. A warehouse whose total is zero is still reported, and ties for top go to the item seen first.

Up nextSets and OperationsDictionaries and Sets

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…