Iterating Dict Items

Concepts covered: Dict Iteration

Once records are keyed in a dict, a loop can walk 3 things: the keys, the values, or both at once. A plain for over a dict walks its keys, in the order they were first inserted. The program below walks the same dict all 3 ways.

plays = {"BR": 140, "SE": 85, "JP": 302}
for code in plays:
    print(code)
for count in plays.values():
    print(count)
for code, count in plays.items():
    print(code, count)

Output:

BR
SE
JP
140
85
302
BR 140
SE 85
JP 302
Loop headerEach step bindsReach for it when
`for code in plays:`a keythe body needs the keys, or reads only some values
`for count in plays.values():`a valuekeys play no part, as in a total
`for code, count in plays.items():`a key and its valuethe body uses both, the common case
person = {"name": "Alice", "age": 25, "city": "NYC"}

for key, value in person.items():
    print(key + ": " + str(value))

print()

config = {"debug": True, "timeout": 30, "max_retries": 3}
print("Current settings:")
for setting, value in config.items():
    print("  " + setting + " = " + str(value))
name: Alice
age: 25
city: NYC

Current settings:
  debug = True
  timeout = 30
  max_retries = 3

.items() delivers each key together with its value, the same shape zip(keys, values) would make, so 2-name unpacking carries over unchanged. A keys loop that reads plays[code] in its body reaches the same values with an extra lookup per step and an extra place to mistype the key.

Counting first, reporting second

A dict is often built by a loop and read by the next. The first loop below counts signups per country: a code seen for the first time gets a new key set to 1, and a repeat adds 1 to the stored count. The second loop reports the totals through .items().

signups = ["SE", "JP", "BR", "JP", "BR", "JP"]
per_country = {}
for code in signups:
    if code in per_country:
        per_country[code] += 1
    else:
        per_country[code] = 1
for code, n in per_country.items():
    print(code, n)

Output:

SE 1
JP 3
BR 2

The report lists SE, then JP, then BR, which is the order the codes first appeared in signups. A dict keeps insertion order and nothing more, so a report sorted by name or by count needs a sorting step of its own.

Forgetting .items()

Drop .items() from the header and the loop goes back to walking keys, so for code, count in plays: tries to split each key into 2 names. What happens next depends on the key. A key like "Alice" has 5 characters, and Python stops with ValueError: too many values to unpack (expected 2). A 2-letter country code has exactly 2 characters, so the split succeeds: code gets the first letter, count gets the second, and the loop runs to the end printing nonsense.

plays = {"BR": 140, "SE": 85, "JP": 302}
for code, count in plays:
    print(code, count)

Output:

B R
S E
J P

Filtering into a new dict

A filtered result goes into a new dict that the loop fills as it walks the original, which is the first step of the animation below, followed by a curve applied to every score and a search for the top scorer.

scores = {"Alice": 85, "Bob": 92, "Charlie": 78, "Diana": 95}

passing = {}
for name, score in scores.items():
    if score >= 80:
        passing[name] = score
print("Passing:", passing)

for name, score in scores.items():
    scores[name] = score + 5
print("Curved:", scores)

top_name = None
top_score = -1
for name, score in scores.items():
    if score > top_score:
        top_score = score
        top_name = name
print("Top:", top_name, top_score)
Passing: {'Alice': 85, 'Bob': 92, 'Diana': 95}
Curved: {'Alice': 90, 'Bob': 97, 'Charlie': 83, 'Diana': 100}
Top: Diana 100
Do
  • Use .items() whenever the body needs both the key and its value
  • Use .values() for totals and checks where the keys play no part
  • Build filtered or reshaped results in a new dict
Avoid
  • Unpack 2 names from a dict without .items()
  • Look up d[k] in a keys loop when .items() already hands you the value

This dict has a 2-letter key and a 3-letter key. What does the loop print?

plays = {"US": 9, "GBR": 4}
for code, count in plays:
    print(code, count)

Every error of this kind is fixed in the header, never in the body. With .items() added, each step offers exactly 2 parts, a key and its value, whatever the length of the key.

About this lesson

This section is part of the Loops: Intermediate lesson on DataDriven, the home of data engineering. Lessons cover SQL, Python, Spark, data modeling and pipeline architecture, and each section pairs its explanation with worked examples and practice you run as you go.