Iterating Through Strings with For Loops
Character counting uses a dictionary to store each unique character and its count.
From Letters to Counts
Suppose you want to know how many times each character appears in the word "brontosaurus". A dictionary can store this information by using each unique character as a key and its occurrence count as the value. A for loop examines the string one character at a time, and the counting logic decides whether that character is new or has already been counted.
The central decision is simple: a character seen for the first time receives a count of 1; a character already in the dictionary has its existing count increased by 1.
Tracing the Dictionary
The dictionary changes after every loop iteration. At the beginning, it is empty. When the loop reaches the first character, that character is not yet a key, so the dictionary receives a new entry with the value 1. Later, a repeated character does not create another key. Instead, its existing value increases.
The important change occurs when the second o is processed. The key o already exists with a count of 1, so the value becomes 2. The loop still processes one character at a time, but the dictionary update depends on whether that character has appeared before.
The Conditional Method
The most explicit approach checks whether the current character is already a key in the dictionary. If it is not present, the code creates an entry with a count of 1. If it is present, the code adds 1 to the stored count.
word = "brontosaurus" d = {} for c in word: if c not in d: d[c] = 1 else: d[c] = d[c] + 1
Processing the First Six Characters
Trace the dictionary while processing the characters b, r, o, n, t, and o from "brontosaurus".
b: b is not in the empty dictionary, so create the entry b: 1.
r: r is new, so add r: 1 while keeping b: 1.
o: o is new, so add o: 1.
n: n is new, so add n: 1.
t: t is new, so add t: 1.
o again: o is already present with count 1, so increase its value to 2.
{'b': 1, 'r': 1, 'o': 2, 'n': 1, 't': 1}
Why Initialization Matters
Initialization and incrementing are different operations. Initialization creates the dictionary entry because the character has no stored count yet. The value must be 1 because the current loop iteration is the first occurrence. Incrementing is used only after the key exists; it raises the stored count by 1 to include the new occurrence.
The get Method
Python's dictionary get method provides a shorter way to handle both cases. The expression d.get(c, 0) returns the current value for c when c exists. When c does not exist, it returns the supplied default value 0. Adding 1 and assigning the result back to d[c] therefore works for both a new character and an existing character.
Expanding the Single Line
Explain how d[c] = d.get(c, 0) + 1 handles a new character and a repeated character.
New character: If c is not a key, d.get(c, 0) returns the default 0. The expression adds 1 and stores d[c] as 1.
Existing character: If c is already a key, d.get(c, 0) returns its current count. The expression adds 1 and stores the increased value.
Same update rule: Both cases add 1 to a value and assign the result to d[c]. The default value makes the new-character case behave like the first count.
The get method combines initialization and incrementing into one expression.
Two Equivalent Approaches
The conditional approach and the get method approach produce identical character-count dictionaries. They differ mainly in how explicitly they show the two cases. The conditional version names the new-character and existing-character branches separately. The get version uses 0 as the missing-key value, then adds 1 in either case.
| Approach | New character | Existing character | Style |
|---|---|---|---|
| Conditional | Assign 1 | Add 1 to the stored count | More explicit |
| get method | get returns 0, then add 1 | get returns the stored count, then add 1 | More concise |
Use the approach that makes the code clearest to you and your teammates. The conditional form can be easier for beginners to read because it displays each case separately. The get form is shorter and remains readable once the default-value behavior is understood.
Mistakes in Character Counting
Initializing an existing character instead of incrementing it
A repeated character is reset to 1 rather than preserving and increasing its current count.
Fix:
Check whether c is already in d. Initialize only a new character, and increment the existing value otherwise.Incrementing a character before creating its first entry
The counting logic needs an initial value before it can increase that value.
Fix:
For a missing key, create d[c] with the value 1.Treating repeated characters as separate keys
The dictionary should store each unique character with one count that changes as more occurrences are processed.
Fix:
Keep one key for the character and update its value when the character appears again.Assuming the two approaches produce different counts
The two implementations use different syntax but apply the same initialization-or-increment logic.
Fix:
Compare their final dictionaries; both approaches count each character identically.
Practice the Trace
Trace the dictionary after each character in the string "aba" is processed using the conditional approach. Write the dictionary after the first a, after b, and after the final a. Then explain why the final a increments an existing count instead of creating a new entry.
Hints
- Start with an empty dictionary.
- For the first occurrence of a character, assign a count of 1.
- For the second occurrence of a character, increase its existing count by 1.
What do you think happens?
After processing the string "aba" with d[c] = d.get(c, 0) + 1, what dictionary should remain?
Reveal answer
Answer: {'a': 2, 'b': 1}
The first a uses the default 0 and becomes 1. b also uses the default 0 and becomes 1. The final a retrieves its existing count of 1 and increases it to 2.
Key Takeaways
- A for loop processes the string one character at a time.
- A dictionary stores each unique character as a key and its occurrence count as the value.
- The conditional approach initializes a new character to 1 and increments an existing character by 1.
- The get approach uses d.get(c, 0) + 1 to handle both cases in one expression.
- The conditional and get approaches produce identical character-count dictionaries.
Key Takeaways
- Use a dictionary to connect each unique character with its count.
- Initialize a count when a character appears for the first time.
- Increment the stored count when the character appears again.
- The get method uses a default value of 0 to combine both cases in one line.
- Tracing the dictionary after each loop iteration reveals how the final counts are built.