Concepts / Iterating Through Strings with For Loops

Iterating Through Strings with For Loops

Character counting uses a dictionary to store each unique character and its count.

  • Programming

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.

bronto{}before the loop{b: 1}after b{b: 1, r: 1}after r{b: 1, r: 1, o: 1}after o{b: 1, r: 1, o: 1, n:1}after n{b: 1, r: 1, o: 1, n:1, t: 1}after t{b: 1, r: 1, o: 2, n:1, t: 1}after the next o
How does the character-count dictionary change after each character in "brontosaurus" is processed?

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

inspectyesnostore 1store increased countccurrent characterc not in ddictionary membership testd[c] = 1first occurrenced[c] + 1later occurrencedupdated dictionary
When does the code create a new dictionary entry with count 1, and when does it increase an existing count?

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.

maps tomaps tomaps tobcharacter1count for bocharacter2count for o after twooccurrencesncharacter1count for n
How does each processed character map to its corresponding key and count in the dictionary?

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.

python

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.

counts each charactercounts each characteridentical resultif-elseexplicit new or existingcasecharacter countsfinal dictionaryd.get(c, 0) + 1default handles missing keycharacter countsfinal dictionary
How do two different implementations produce the same final character-count dictionary?
ApproachNew characterExisting characterStyle
ConditionalAssign 1Add 1 to the stored countMore explicit
get methodget returns 0, then add 1get returns the stored count, then add 1More 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

EASY

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?

  • {'a': 1, 'b': 1}
  • {'a': 2, 'b': 1}
  • {'a': 3, 'b': 2}
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

  1. A for loop processes the string one character at a time.
  2. A dictionary stores each unique character as a key and its occurrence count as the value.
  3. The conditional approach initializes a new character to 1 and increments an existing character by 1.
  4. The get approach uses d.get(c, 0) + 1 to handle both cases in one expression.
  5. 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.