Concepts / Building Histograms with Dictionaries

Building Histograms with Dictionaries

A histogram built with a dictionary records how often items occur.

  • Programming
Interactive lab

Try it: Counting Words with a Dictionary

The py4e histogram pattern: split each line into words, count them with counts[word] = counts.get(word, 0) + 1, then find the most common word with a max loop or by sorting (count, word) tuples in reverse.

How it works

  1. Optionally remove punctuation with str.translate and lower-case the line, then split() it into words.
  2. For each word: counts.get(word, 0) returns the current count or 0 for a new word; store it plus one (or the if word not in counts form).
  3. A dict remembers insertion order: a word's position is fixed the first time it is seen.
  4. Max loop: keep the word whose count is strictly larger than the best so far (the first word wins a tie).
  5. Or build [(count, word) …], sort with reverse=True (ties ordered by the word, reversed) and slice [:N].

Default run (25 steps): Start with an empty dict. The text has 3 lines. … [:3] keeps the top 3: [(5, 'the'), (2, 'sat'), (2, 'on')].

Simplified: Printable-ASCII text up to 320 characters, 8 lines and 60 words, typed in the lab instead of read from a file or URL.

Educational simulation

Loading the simulation…

From Items to Counts

A histogram built with a dictionary records how often items occur. Each observed item becomes a dictionary key, and its value records the number of times that item has appeared. The main difficulty is the first occurrence: before an item has been counted, its key may not exist in the dictionary. Python's get() method handles that missing-key case by returning a default value.

What do you think happens?

Suppose counts is an empty dictionary and item is the first value being counted. What starting count should get() provide?

  • The current count stored for item

  • 0

  • 1

  • An arbitrary value

Reveal answer
Answer:

0

When the key is missing, get() returns the default supplied as its second argument. Starting from 0 makes it possible to add 1 for the item's first occurrence.

How get() Chooses a Value

The get() method looks up a key in a dictionary. If the key exists, get() retrieves the value associated with that key. If the key is missing, get() returns the default value supplied to it. This makes get() useful when a program cannot assume that every key has already been added.

python
Output
2
0

The first lookup finds the existing key red, so the stored value 2 is returned. The second lookup cannot find blue, so the default 0 is returned. The default does not represent a newly stored key by itself; it is the value produced by the lookup when the key is absent.

Look up keycounts.get(key, 0)Key exists?Stored valueexisting key0missing key defaultyesno
What happens when get() looks up a key that exists versus a key that is missing?

The Counting Idiom

Definition

The standard counting expression is d[c] = d.get(c, 0) + 1. It reads the current count for key c, uses 0 when c is not present, adds 1 for the newly observed item, and stores the resulting count back under c.

Code walkthrough
counts[item] = counts.get(item, 0) + 1
  1. 1
    First, get() retrieves the count associated with item.
  2. 2
    If item is not yet a key, get() supplies 0.
  3. 3
    The expression adds 1 to that count.
  4. 4
    The assignment stores the new total under item.
  • counts[item]: the dictionary entry that receives the updated count
  • counts.get(item, 0): the existing count, or 0 when item is missing
  • + 1: adds the current occurrence
Worked example

Counting Three Items

Start with an empty dictionary and process the items red, blue, and red.

  1. 1
    Process red

    red is missing, so get() returns 0. Adding 1 produces 1, which is stored for red.

  2. 2
    Process blue

    blue is missing, so get() returns 0. Adding 1 produces 1, which is stored for blue.

  3. 3
    Process red again

    red already has the count 1. Adding 1 produces 2, which replaces the previous count for red.

Result

{"red": 2, "blue": 1}

Empty counts{}red{"red": 1}blue{"red": 1, "blue": 1}red{"red": 2, "blue": 1}count itemcount itemcount item
How does each input item move through the loop and update its corresponding key-value count?

Refactoring the Loop

Before get() is used, a counting loop commonly needs explicit logic for the two cases: the key is already present, or the key is missing. The get() idiom puts both cases into one assignment. The result is more concise and is described in the source material as more Pythonic and less error-prone when keys may not exist.

Before
counts = {}
for item in items:
    if item in counts:
        counts[item] = counts[item] + 1
    else:
        counts[item] = 1

The loop explicitly branches depending on whether item is already a key.

After
counts = {}
for item in items:
    counts[item] = counts.get(item, 0) + 1

get() supplies 0 for a missing key, so one assignment handles both cases.

The two versions express the same counting idea. In the longer version, the missing-key case assigns 1 directly. In the shorter version, the missing-key case starts at 0 and then adds 1. For an existing key, both versions increase the previous count by 1.

if item in countsbranch for existing ormissing keycounts.get(item, 0) +1one counting expressionrefactor
How does control flow change when the explicit missing-key check is replaced with counts.get(item, 0) + 1?

Mistakes with Missing Keys

  • Common mistake

    Using bracket notation as though every key already exists

    What it looks like
    counts[item] = counts[item] + 1
    Why it fails

    The counting expression assumes that item already has a stored count, but the first occurrence may arrive before that key has been added.

    Do this instead

    Use counts[item] = counts.get(item, 0) + 1 so a missing key starts from the default count 0.

  • Common mistake

    Forgetting to add 1 after retrieving the count

    What it looks like
    counts[item] = counts.get(item, 0)
    Why it fails

    The lookup retrieves the old count or the default, but it does not increase the total for the current occurrence.

    Do this instead

    Add 1 before storing the result: counts[item] = counts.get(item, 0) + 1.

  • Common mistake

    Using a default other than 0 for a new count

    What it looks like
    counts[item] = counts.get(item, 1) + 1
    Why it fails

    A new item would begin at 1 and then be increased again, so its first occurrence would be counted as 2.

    Do this instead

    Use 0 as the default starting count, then add 1 for the current item.

Practice the Pattern

EASY

Write a loop that builds a histogram for the items in the list ["cat", "dog", "cat", "bird", "dog", "cat"]. Use get() rather than an if-statement. What dictionary should the loop produce?

Hints
  • Begin with an empty dictionary named counts.
  • For each item, assign counts[item] the result of counts.get(item, 0) + 1.
  • The item cat occurs three times, dog occurs two times, and bird occurs one time.
python
Output
{"cat": 3, "dog": 2, "bird": 1}

Key Takeaways

  1. 1
    get() returns the stored value when a dictionary key exists.
  2. 2
    When the key is missing, get() returns the supplied default value.
  3. 3
    The counting idiom d[c] = d.get(c, 0) + 1 handles first and later occurrences in one line.
  4. 4
    A dictionary histogram maps each observed item to its occurrence count.
  5. 5
    Using get() avoids a separate missing-key branch and is more Pythonic and less error-prone for this counting pattern.

At a glance

  • get() retrieves an existing dictionary value or returns a chosen default for a missing key.
  • The default 0 represents the number of earlier occurrences before the current item is counted.
  • The expression d[c] = d.get(c, 0) + 1 replaces a longer if-statement counting pattern.
  • Repeatedly applying this expression builds a histogram of item frequencies.

Related concepts

More concepts starting with B