Skip to content

Beginner: data foundations · Python for data · topic 2 of 62 · 30 min

Python essentials for data: records, lists and dictionaries

Explanation

A table can live in plain Python as a list of dictionaries: each dictionary is one row, and its keys are the column names. List comprehensions filter and transform rows in one line, sorted() with key=lambda sorts by any column, and min, max, zip and enumerate finish the toolkit.

A quick recap

You already know variables, if, for loops and functions from the Python course. Two built-in types matter most for data. A list holds items in order, written in square brackets: [250, 900, 120]. A dictionary (dict) holds pairs of key and value, written in curly brackets: {"city": "Pune", "amount": 250}. You read a value by its key: row["city"] gives "Pune".

A table as a list of dictionaries

Why combine them? Because a table is a list of rows, and each row is a set of named values. So a list of dicts is a table: each dict is a row (also called a record), and the keys are the column names. This is the same shape you get from a CSV file or a JSON API, which you will meet in the next topic.

python
orders = [
    {"id": 1, "city": "Pune", "amount": 250},
    {"id": 2, "city": "Delhi", "amount": 900},
    {"id": 3, "city": "Pune", "amount": 120},
    {"id": 4, "city": "Chennai", "amount": 640},
]
print(orders[1]["city"])   # Delhi
print(len(orders))         # 4
orders[1] is the second row (counting starts at 0), and ["city"] picks one column from it.
Think of it like this: Think of a stack of printed bills. Each bill (a dict) has the same labelled boxes: bill number, city, amount. The stack in order is the list. Filtering is pulling out some bills; sorting is rearranging the stack.

List comprehensions: filter and transform

A list comprehension builds a new list from an old one in a single line. The pattern is [what_to_keep for item in items if condition]. The if part is optional. It is shorter than a for loop with append, and it does not change the original list.

python
big = [o for o in orders if o["amount"] >= 500]
print([o["id"] for o in big])          # [2, 4]

amounts = [o["amount"] for o in orders]
print(amounts)                         # [250, 900, 120, 640]

with_gst = [round(a * 1.18, 2) for a in amounts]
print(with_gst)                        # [295.0, 1062.0, 141.6, 755.2]
Filtering keeps some rows; transforming makes a new value from each row. Taking one key from every row is called extracting a column.

A dict comprehension works the same way with curly brackets: {o["id"]: o["amount"] for o in orders} gives {1: 250, 2: 900, 3: 120, 4: 640}, a quick lookup from id to amount.

Sorting by a column

sorted() returns a new sorted list. Python cannot guess how to compare two dicts, so you pass key: a small function that takes one row and returns the value to sort by. lambda makes such a one-line function without a name: lambda o: o["amount"] means "given o, return its amount". reverse=True sorts from largest to smallest.

python
by_amount = sorted(orders, key=lambda o: o["amount"], reverse=True)
print([o["id"] for o in by_amount])   # [2, 4, 1, 3]

print(max(orders, key=lambda o: o["amount"])["city"])   # Delhi
print(min(orders, key=lambda o: o["amount"])["id"])     # 3
max and min take the same key, and return the whole row with the biggest or smallest value.

Python's sort is stable: rows with equal keys stay in their original order. That lets you sort by two columns at once with a tuple key, such as key=lambda o: (o["city"], -o["amount"]) for city A to Z and, inside each city, the biggest amount first.

zip and enumerate

zip walks over two or more lists side by side, pairing the first items, then the second items, and so on. enumerate gives you a counter next to each item, which is handy for ranks and row numbers.

python
names = ["Asha", "Ravi", "Meena"]
marks = [78, 91, 65]
print(dict(zip(names, marks)))   # {'Asha': 78, 'Ravi': 91, 'Meena': 65}

for rank, o in enumerate(by_amount, start=1):
    print(rank, o["city"], o["amount"])
# 1 Delhi 900
# 2 Chennai 640
# 3 Pune 250
# 4 Pune 120
zip stops at the shortest list, so check that your lists have the same length.

Common mistakes

  • Writing rows = rows.sort(...). list.sort() sorts in place and returns None, so rows becomes None. Fix: use rows.sort(...) on its own line, or new_rows = sorted(rows, ...).
  • A KeyError when a row is missing a column. Fix: use row.get("city"), which gives None instead of crashing, or row.get("city", "Unknown") for a default.
  • Sorting numbers stored as text: sorted(["100", "20", "3"]) gives ['100', '20', '3'] because text is compared letter by letter. Fix: convert with int() or float() first, or use key=int.
  • Changing a list while looping over it (removing rows inside the loop). Fix: build a new list with a comprehension instead.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Python essentials for data: records, lists and dictionaries · 1/7

Tables in plain Python

In this lesson you will hold a whole table in plain Python, and filter, sort and summarise it.

Prefer a video by a teacher? Find free videos on “python list of dictionaries list comprehension sorted key lambda” on YouTube ↗

In real life: Top products on a shopping site

An analyst at an online store like Flipkart or Meesho often gets product data from an internal API as a list of records. To answer "which phones under ₹15,000 have the best rating?", she filters the records, sorts them by rating and takes the first few. pandas does this on millions of rows, but the idea is exactly this.

python
phones = [
    {"name": "Phone A", "price": 12999, "rating": 4.3},
    {"name": "Phone B", "price": 18999, "rating": 4.6},
    {"name": "Phone C", "price": 9999, "rating": 4.1},
    {"name": "Phone D", "price": 14499, "rating": 4.5},
]
budget = [p for p in phones if p["price"] < 15000]
best = sorted(budget, key=lambda p: p["rating"], reverse=True)
for rank, p in enumerate(best, start=1):
    print(rank, p["name"], p["rating"])
Output: 1 Phone D 4.5, then 2 Phone A 4.3, then 3 Phone C 4.1.

Practice (0/3 done)

Task 1 · Code · Python

Write big_orders(orders, min_amount) that returns a new list of the order dicts whose "amount" is at least min_amount, in their original order. Example: with min_amount 500, an order of 500 is kept.

Task 2 · Code · Python

Write sort_by_price(products) that returns a NEW list of product dicts sorted by "price" from low to high. Products with the same price keep their original order. The original list must not change.

Task 3 · Code · Python

Write column(rows, key) that returns the list of values in one column: row[key] for each row, in order. If a row does not have that key, put None for it instead of crashing.

Quick quiz

Question 1

1.rows = [{"a": 1}, {"a": 5}, {"a": 3}]. What is [r["a"] for r in rows if r["a"] > 2]?

Question 2

2.What does x = [3, 1, 2].sort() store in x?

Question 3

3.Which call sorts the list people by "age", oldest first?

Question 4

4.What is list(zip(["a", "b", "c"], [1, 2]))?

Question 5

5.row = {"city": "Pune"}. What does row.get("amount", 0) return?

Read more (free)

Before this, learn

This topic builds on these. If something here feels new, open them first.

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

rows = [{"a": 1}, {"a": 5}, {"a": 3}]. What is [r["a"] for r in rows if r["a"] > 2]?

Answer: [5, 3]

The comprehension keeps rows where a is above 2, in their original order: 5, then 3.

What does x = [3, 1, 2].sort() store in x?

Answer: None

list.sort() sorts in place and returns None. Use sorted() to get a new list.

Which call sorts the list people by "age", oldest first?

Answer: sorted(people, key=lambda p: p["age"], reverse=True)

key tells sorted which value to compare, and reverse=True puts the largest first.

What is list(zip(["a", "b", "c"], [1, 2]))?

Answer: [("a", 1), ("b", 2)]

zip stops at the shortest input, so "c" is silently dropped.

row = {"city": "Pune"}. What does row.get("amount", 0) return?

Answer: 0

get returns the default you give (0) when the key is missing.

Which line is valid Python?Related

Answer: ["even" if x % 2 == 0 else "odd" for x in nums]

An if-else choice goes before the for. A lone if (a filter) must go after the for.

From List, dict and set comprehensions

What does it mean that Python sorting is stable?Related

Answer: Items with equal keys keep their original order

A stable sort keeps the earlier of two equal items first.

From Sorting with key

What does for k, v in d.items(): give you in each step?Related

Answer: A key and its value

items() gives (key, value) pairs, and the loop unpacks each pair into k and v.

From Dictionaries: look things up by name

Which LINQ method transforms each item into something else?Related

Answer: Select

Select maps each item to a new value.

From LINQ basics: query data in a few lines

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 3 more topics in “Python for data” before its exam: Reading CSV and JSON with the standard library, Counting and grouping: collections and statistics, Writing data code that others can trust.
  2. Module 1 exam: Python for data · 14 questions · 20 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Statistics made simple. 62 topics left in the course before the final exam.

← Previous: What data science is, and how this course works