Concepts / Introduction to Dictionaries

Introduction to Dictionaries

Dictionaries outperform lists and variables for character counting because they only allocate space for characters that actually appear, not for every possible character.

  • Programming

The Counting Challenge

Suppose you want to discover which letters appear most frequently in the word brontosaurus. The result should record that r, o, s, and u each appear twice, while b, n, t, and a each appear once. This task is called frequency counting. The collection of counters that records these frequencies is called a histogram.

The difficult part is not adding one to a counter. The important design decision is how to store the counters. You can use separate variables, a list, or a dictionary. All three approaches can solve the same counting problem, but they differ in how much you must know before processing the input and how much unused space they reserve.

requiresrequiresstoresVariablesone counter per plannedcharacterKnown character setdecided in advanceListpositions for plannedcharactersObserved charactersadded as neededDictionarykeys for observedcharacters
How do variables, a list, and a dictionary represent character counts differently, and what trade-offs does each approach have?

Why Dictionaries Adapt

The first two approaches require you to decide in advance which characters might appear. For example, a design using 26 variables or a 26-element list reserves room for every letter of the alphabet, including letters that never occur in the input. A dictionary takes a different approach: it creates an entry only when a character actually appears.

This matters when the possible input is not limited to English letters. A string might include digits, punctuation, or Unicode symbols. A list-based design requires you to know the possible character range and how to map each character to a numeric position. A dictionary can use the arriving character as a key, so the counting pattern does not need a new variable or a preallocated position for every possible character.

list or variables reservedictionary createsstoresstoresInputa string with few distinctcharactersAll planned letters26 positions or countersbcountObserved entriesonly characters that appearocount
What space is represented when the input contains only a few distinct characters?

The Two-Branch Counting Rule

The dictionary algorithm has one decision point. For each character c, check whether c is already a key in the dictionary d. If it is not present, create the key and give it the value 1. If it is already present, increment its existing value. The pattern is commonly written as if c not in d.

d = {} for c in "brontosaurus": if c not in d: d[c] = 1 else: d[c] = d[c] + 1 print(d)

What do you think happens?

What dictionary will the loop contain after it processes the entire word brontosaurus?

  • A dictionary with one entry for every character position
  • A dictionary with one entry for each distinct character and its frequency
  • A dictionary containing only the last character
  • An empty dictionary because no keys were known in advance
Reveal answer

Answer: A dictionary with one entry for each distinct character and its frequency

The dictionary creates a key the first time a character appears and increments that key on later encounters. The completed histogram is {'b': 1, 'r': 2, 'o': 2, 'n': 1, 't': 1, 's': 2, 'a': 1, 'u': 2}.

Reading the State Changes

The word brontosaurus contains 12 characters but only 8 unique letters. On a first encounter, the dictionary gains a new key with value 1. On a later encounter, no new key is needed; the value belonging to the existing key increases.

b is newr is newo is newr becomes 2o becomes 2n is new{}before reading{b: 1}read b{b: 1, r: 1}read r{b: 1, r: 1, o: 1}read o{b: 1, r: 2, o: 1}read r again{b: 1, r: 2, o: 2}read o again{b: 1, r: 2, o: 2, n:1}read n
How does the dictionary change after each character is read, including first encounters and repeated characters?
Character readDecisionDictionary state
bNew key, so initialize b to 1{'b': 1}
rNew key, so initialize r to 1{'b': 1, 'r': 1}
oNew key, so initialize o to 1{'b': 1, 'r': 1, 'o': 1}
rExisting key, so increase r to 2{'b': 1, 'r': 2, 'o': 1}
oExisting key, so increase o to 2{'b': 1, 'r': 2, 'o': 2}
nNew key, so initialize n to 1{'b': 1, 'r': 2, 'o': 2, 'n': 1}

The first six processed characters show both branches of the counting rule.

maps tomaps tomaps torcharacter key2frequency valueocharacter key2frequency valuebcharacter key1frequency value
How does each input character become a dictionary key, and how does its corresponding value change?

Choosing the Flexible Structure

ApproachWhat must be known firstHow it stores countsMain trade-off
Separate variablesThe characters to countA different counter for each planned characterWorks for a fixed known set, but does not adapt naturally to unexpected characters
ListThe character range and a mapping to positionsA counter at a position for each planned characterCan work for English letters, but reserves positions for letters that may not appear
DictionaryNo complete character setA key for each character that appears and a value for its frequencyAdapts to letters, digits, punctuation, and Unicode symbols while storing only observed entries

A list can be a reasonable choice when you know that the input contains only English letters and you are willing to convert characters to list positions with ord(). However, that approach depends on the known character range. The dictionary pattern keeps the same counting logic when the input later changes to words, multiple languages, digits, punctuation, or other symbols.

Mistakes in Frequency Counting

  • Treating every character as new

    Repeated characters should increase the value of the existing key rather than create another count for the same character.

    Fix: Check if c not in d. Initialize a new key only when the character is absent; otherwise increment d[c].

  • Preallocating a fixed set when the input is broader

    The design requires you to know the full range of possible characters and their positions in advance.

    Fix: Use the character itself as a dictionary key so the dictionary can create entries as new characters appear.

  • Confusing a histogram with a graph only

    In computing, a histogram can simply be a collection of counters.

    Fix: Recognize the dictionary of keys and frequency values as the histogram, even when it is printed as key-value pairs.

Practice the State Trace

EASY

Trace the dictionary while processing the string "level". Write the dictionary after each character is read. Then identify which characters were initialized and which characters were incremented.

Hints
  • Start with an empty dictionary.
  • The first l, e, and v are new characters.
  • The second e and the second l use the existing-key branch.

Tracing level

Determine the dictionary state after each character in the string level.

Read l: l is new, so create the entry l: 1.

Read e: e is new, so create the entry e: 1.

Read v: v is new, so create the entry v: 1.

Read e again: e already exists with value 1, so increase it to 2.

Read l again: l already exists with value 1, so increase it to 2.

{'l': 2, 'e': 2, 'v': 1}

Key Takeaways

  1. Character frequency counting can use separate variables, a list, or a dictionary.
  2. Variables and lists require more advance knowledge about the characters that may appear; a dictionary adapts as characters arrive.
  3. The central dictionary pattern is: if a character is new, initialize its count to 1; otherwise increment its existing count.
  4. A dictionary histogram stores each observed character as a key and its frequency as the corresponding value.
  5. Dictionaries are especially useful when the input may include unexpected characters or when storing entries only for observed characters is preferable.

Key Takeaways

  • A dictionary represents a frequency table with character keys and count values.
  • The if c not in d pattern distinguishes first encounters from repeated encounters.
  • Dictionaries store entries only for characters that actually appear, unlike a fixed collection of variables or positions.
  • The same approach can adapt to letters, digits, punctuation, Unicode symbols, words, and other frequency-counting tasks.