# 13.6 Lists and dictionaries (/building-ai-workers/programming-fundamentals/lists-and-dictionaries)

---
type: Document
title: "13.6 Lists and dictionaries"
description: "What a lookup does with a missing key, and what a sort compares."
status: stable
order: 313.06
ksor:
  owner: team:panaversity
  audience: [ public ]
  approval:
    by: process:panaversity
    at: 2026-11-10T15:33:14Z
chapter: "13"
part: III
expert_status: builder-only
concepts: [ "13.6" ]
last_verified: 2026-10-30
generated:
  at: 2026-11-10T15:33:14Z
  by: process:panaversity
trust_tier: unverified
build_id: sha256:46fd53c5d7ab1c14f6347908d45c9fdaecda4d914439923ee878bdcecd57803e
dirty: true
ksor_version: 0.0.60
---

**In everyday life.** A grocery **list** is in order: first milk, then bread. A coat check finds your coat by its ticket number, and a ticket they never gave out gets you nothing.

**What you will learn.** Two questions for every sort and lookup: what does it compare, and what if the name is missing?

**Why it matters.** A count and a total cannot see a wrong order or a missing name.

### List or dictionary?

A **list** holds items in order, like the grocery list, and you find each one by its position. A **dictionary** is the coat check. It holds values under names, called **keys**, as the coat check holds coats under ticket numbers. One looks like `{ V005: "Hocking Valley Pallets" }`. TypeScript uses an **object**, written with braces, and Python a `dict`.

In [13.4](decisions-and-repetition.md#how-does-code-do-the-same-thing-to-every-item), each invoice was a list, and you had to remember that position 1 was the status. A **record** gives each value a name instead. It is a dictionary that holds one thing, such as one invoice. So `inv[1]` becomes `inv.status` in TypeScript and `inv["status"]` in Python.

![Figure 13.7. The INV-8301 row of invoices.csv becoming a record. The header names become keys, the cells become values, and the amount "482500" is converted from text to the whole number 482500. Blank or invalid amounts are rejected.](img/row-to-record.png)

*Figure 13.7. A row becomes a record. The header gives the keys. Every value starts as text until the code converts it.*

### What does a sort compare, and why can't my count and total see it?

It compares what its rule says. To sort a stack of invoices by hand, you take two at a time and decide which goes first, until the whole stack is in order. A sort does the same, and its rule is that one decision. With no rule, it uses a default, and the two languages differ. So read every sort line an agent writes.

**At work.** Ana's check from [Chapter 12](../agentic-coding/from-chat-to-coding-agent.md) says Friday has 8 invoices, $19,229.53. The controller asks for Friday's list, largest first. The agent sorts it, the tests pass, and its summary matches her check. Before the agent runs the list, she reads the one line that changed.

```ts tab="TypeScript" tab-group="language"
// take two invoices, a and b: the larger amount goes first
friday.sort((a, b) => b.cents - a.cents);
```

```python tab="Python" tab-group="language"
# compare each invoice by its cents, largest first
friday.sort(key=lambda inv: inv["cents"], reverse=True)
```

`friday` is the list of Friday's invoices. The line is the hand sort's one decision: which of two invoices goes first. Each language writes that decision its own way.

| Language | How to read the rule |
| --- | --- |
| TypeScript | `(a, b) => b.cents - a.cents` takes two invoices, `a` and `b`, and subtracts their amounts. A positive answer puts `b` first and a negative answer puts `a` first, so the larger amount comes first. |
| Python | `lambda` makes a small function with no name. `lambda inv: inv["cents"]` says "compare each invoice by its cents", and `reverse=True` puts the largest first. |

She writes in `NOTES.md`: "It compares the amounts as numbers, largest first." So she predicts INV-8305, at 735000 cents, first, and INV-8312, at 19995 cents, last.

The run prints those two first and last. But a count and a total come out the same in any order, so her check cannot see this line. So she lists amounts of different lengths in the order they must come out, and has the agent turn her list into a test. It passes, and it will fail if a later change breaks the order.

### What does a sort do when it has no rule?

It uses a default, and here the two languages differ. TypeScript's `cents.sort()` compares numbers as text, one character at a time, as if putting words in alphabetical order. So 482500 comes before 61875, because 4 comes before 6. Python's `sorted` compares numbers as numbers, unless `key=str` tells it to compare them as text. Amounts of different lengths are where this shows. Predict both lines.

```ts tab="TypeScript" tab-group="language"
const cents = [735000, 482500, 61875];
console.log(cents.sort());                  // no rule
console.log(cents.sort((a, b) => a - b));   // rule: the smaller number first
```

```python tab="Python" tab-group="language"
cents: list[int] = [735000, 482500, 61875]
print(sorted(cents))            # no rule
print(sorted(cents, key=str))   # rule: compare them as text
```

```text tab="TypeScript" tab-group="language"
[ 482500, 61875, 735000 ]
[ 61875, 482500, 735000 ]
```

```text tab="Python" tab-group="language"
[61875, 482500, 735000]
[482500, 61875, 735000]
```

### What happens to a missing key?

Think of a ticket the coat check never gave out. TypeScript hands you nothing, `undefined`, and keeps running. Python stops with a `KeyError`. A key must match exactly, capital letters too, so `v005` is not `V005`. A position past the end of a list is missing in the same way: `undefined` in TypeScript, an `IndexError` in Python.

**At work.** Brightline's export names each vendor by id, such as `V005`. To print names, the script builds a dictionary from `vendors.csv` and looks up each invoice's vendor id. Ana asks: what happens when an invoice names an id that is not in the dictionary?

`names` is a dictionary of many vendors, with each name kept under its id. Python also has a careful way to ask: `.get()` gives `None` for a missing key, or a default you pass it, as in `.get(key, 0)`. Predict each line.

```ts tab="TypeScript" tab-group="language"
// names: a dictionary whose keys and values are text
const names: Record<string, string> = { V001: "Midwest Packaging Co.", V005: "Hocking Valley Pallets" };
console.log(names["V005"]);   // a ticket it gave out
console.log(names["V099"]);   // a ticket it never gave out
```

```python tab="Python" tab-group="language"
# names: a dictionary whose keys and values are text
names: dict[str, str] = {"V001": "Midwest Packaging Co.", "V005": "Hocking Valley Pallets"}
print(names["V005"])       # a ticket it gave out
print(names.get("V099"))   # never gave out, asked with .get()
print(names["V099"])       # never gave out, asked directly
```

```text tab="TypeScript" tab-group="language"
Hocking Valley Pallets
undefined
```

```text tab="Python" tab-group="language"
Hocking Valley Pallets
None
Traceback (most recent call last):
  ...
KeyError: 'V099'
```

### Try it

The file in `13-6` holds a lookup and a sort. Run it and investigate, as in [13.1](you-read-the-agent-writes.md#try-it). Watch the missing vendor, `V099`.

**Modify.** Send: "Please change the sort in the file to put the largest amount first. Don't run it yet." The amounts are 735000, 482500 and 61875. Say which will come first. Then ask the agent to run it.

**Make.** Send: "Please make a new file in 13-6 called mine that keeps each vendor's terms under its id, looks up one vendor that exists and one that doesn't, and prints both. Don't run it yet." Say what the missing one will print, and then ask the agent to run it.

**What you should see.** `735000` comes first after your change. In `mine`, the missing vendor gives `undefined` in TypeScript. In Python, it depends on how the agent looked it up, so read that line.

**The operating rule:** for every lookup, ask what happens when the key is missing. For every sort, ask what it compares.

**Next.** Those values arrive from files, as text and dates. [13.7](text-dates-files.md) shows their hidden rules.
