Iterating Through Dictionaries

Introduction

Welcome back to Organizing Data with Dictionaries in Python! With two units behind us, we are now at the third of four, and our toolkit is growing nicely.

So far, every operation we have performed has targeted a single key: we read one value, overwrote one field, and removed one entry. That is fine when we know exactly which key we care about, but plenty of everyday tasks are not like that. Printing a full inventory report, adding up every quantity in a warehouse, or picking out the products that need reordering all require visiting every entry, one after another.

That is exactly what dictionary iteration gives us. In this lesson, we will learn three closely related methods:

  1. keys(), to walk through the labels;
  2. values(), to walk through the data;
  3. items(), to walk through both halves at the same time.

Our running example will be a small shop inventory holding four items. By the end, we will have printed a tidy report of it and built a list of everything that is out of stock.

The Inventory We Will Loop Over

Every section that follows works on the same dictionary, so let us fix it in our minds first. It maps four fruit names to the number of units currently on the shelf.

Python
inventory = {
    "apples": 12,
    "bananas": 0,
    "cherries": 45,
    "dates": 3,
}

A few things are worth noticing about the shape of this data:

  • The keys are strings naming a product, and the values are integers counting units, so every entry answers the question "How many of this do we have?"
  • "bananas" deliberately has a value of 0. It is a perfectly valid entry, not a missing one, and it will become the star of our filtering example later on.

Also recall that dictionaries preserve insertion order: our loops will visit "apples" first and "dates" last, matching the order in which we wrote them.

Looping Over Keys with keys()

The most natural place to start is with the labels. The keys() method hands us the dictionary's keys, one at a time, and a for loop consumes them just as it consumed list elements in the earlier course.

Python
# Iterating a dict yields its keys by default
for item in inventory.keys():
    print("Item:", item)

On each pass, the loop variable item is bound to a single key: first the string "apples", then "bananas", and so on. Two details deserve attention:

  • Writing for item in inventory: produces the exact same result because plain iteration over a dictionary yields its keys. Many programmers still spell out keys() to make that intent obvious to a reader.
  • A common expectation is that looping over a dictionary gives us the values. It does not; we get the keys, and if we want a value, we must ask for it.
text
Item: apples
Item: bananas
Item: cherries
Item: dates

Summing Values with values()

When the labels are irrelevant and only the numbers matter, values() is the view we want. It yields the values alone, in the same order as their keys, which makes it a perfect input for a built-in function like sum().

Python
# values() yields the values
print("Total units:", sum(inventory.values()))

Notice that no for loop appears here at all. sum() walks through the values on our behalf and adds them up: 12+0+45+3=6012 + 0 + 45 + 3 = 60. We could certainly write the loop by hand, starting a total variable at 0 and adding each value to it, and the answer would be identical; sum() simply says the same thing in one line.

One practical note: values() gives back a view object rather than a list, so printing it directly shows a wrapper. To inspect the raw numbers, we would write list(inventory.values()).

text
Total units: 60

Looping Over Pairs with items()

Most reports need the label and the number together, and that is where items() shines. Each pass through the loop yields one key-value pair, and two loop variables unpack that pair in a single step.

Python
# items() yields key-value pairs together
for item, count in inventory.items():
    print(f"{item}: {count}")

On the first iteration, item becomes "apples" and count becomes 12, with no extra lookup required. The alternative would be to loop over keys and write inventory[item] inside the body; that works, but it repeats the dictionary name and performs a second search for data we already had in hand.

The three dictionary views expose different parts of the same ordered entries:

Diagram comparing the keys, values, and item pairs yielded from the inventory dictionary

This table sums up which view to reach for:

MethodYields on each passReach for it when
keys()A single keyWe only need the names
values()A single valueWe only need the data
items()A key and a valueWe need both halves

Here is the report our items() loop prints:

text
apples: 12
bananas: 0
cherries: 45
dates: 3

Filtering Entries While Iterating

Now let us answer a real question: Which products have run out? This calls for the accumulator pattern, where we start with an empty list and add to it only when a condition holds.

Python
# Filter entries by their value while iterating
out_of_stock = []
for item, count in inventory.items():
    if count == 0:
        out_of_stock.append(item)
print("Out of stock:", out_of_stock)

Tracing the four passes shows why only one name survives: 12 is not 0, so "apples" is skipped; 0 passes the test, so "bananas" is appended; 45 and 3 both fail. The key idea is that we decide based on the value but collect the key, which is only possible because items() gave us both.

One safety habit: adding or deleting keys while a loop over a dictionary is running raises a RuntimeError. Collecting the interesting keys first and modifying the dictionary afterward avoids the problem entirely.

text
Out of stock: ['bananas']

Putting It All Together

Let us see all four techniques as a single flow: list the items, total the units, print the report, then flag what needs restocking.

Python
inventory = {
    "apples": 12,
    "bananas": 0,
    "cherries": 45,
    "dates": 3,
}

for item in inventory.keys():
    print("Item:", item)

# values() yields the values
print("Total units:", sum(inventory.values()))

# items() yields key-value pairs together
for item, count in inventory.items():
    print(f"{item}: {count}")

# Filter entries by their value while iterating
out_of_stock = []
for item, count in inventory.items():
    if count == 0:
        out_of_stock.append(item)
print("Out of stock:", out_of_stock)

Each block of output traces back to one view: the four Item: lines come from keys(), the total comes from values(), the formatted report comes from items(), and the final list comes from items() paired with a condition.

text
Item: apples
Item: bananas
Item: cherries
Item: dates
Total units: 60
apples: 12
bananas: 0
cherries: 45
dates: 3
Out of stock: ['bananas']

Conclusion and Next Steps

Nicely done: our dictionaries are now something we can sweep through from end to end. We have three views to choose from, and the decision rule is refreshingly simple: keys() when we only need the names, values() when we only need the data, and items() when we need both together. We also layered two patterns on top of them: aggregating, where sum() consumes values() in a single line, and filtering, where a loop over items() tests each value and appends the matching key to an accumulator list. Along the way, we saw that plain iteration over a dictionary already yields keys, that views are not lists until we convert them, and that changing a dictionary's set of keys mid-loop is a habit to avoid.

The practices coming up put all of this in your hands: you will print item names from an inventory, total its values, format each pair into a report line, and filter entries into a list of your own. After that, the final unit takes a bigger step, nesting lists and dictionaries inside one another to model records with real depth. Let us go loop through some data!

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal