Lists, dicts & comprehensions in depth

You met lists and dictionaries in the basics lesson. Real programs spend most of their time moving data between these structures, so knowing the idioms well makes your code shorter, faster and easier to read.

Slicing and copying lists

A slice has the form items[start:stop:step]. The start is included, the stop is excluded, and any part can be skipped.

months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
print(months[:3])      # ['Jan', 'Feb', 'Mar']  - first quarter
print(months[::2])     # ['Jan', 'Mar', 'May']  - every second month
print(months[::-1])    # reversed copy

backup = months[:]     # shallow copy; months.copy() does the same

Sorting with a key

sorted() returns a new list, while list.sort() sorts in place and returns None. The key argument decides what to compare.

orders = [
    {"id": 101, "city": "Surat", "amount": 4200},
    {"id": 102, "city": "Indore", "amount": 950},
    {"id": 103, "city": "Kochi", "amount": 7800},
]
top = sorted(orders, key=lambda o: o["amount"], reverse=True)
print([o["id"] for o in top])   # [103, 101, 102]

Dictionary techniques

Task Idiom
Read with a fallback d.get("key", 0)
Loop over pairs for k, v in d.items():
Merge two dicts merged = a \| b (Python 3.9+)
Count things collections.Counter(items)
Group into lists collections.defaultdict(list)
from collections import Counter, defaultdict

sales = [("Surat", 4200), ("Indore", 950), ("Surat", 1300), ("Kochi", 7800)]

by_city = defaultdict(list)
for city, amount in sales:
    by_city[city].append(amount)

totals = {city: sum(vals) for city, vals in by_city.items()}
print(totals)                       # {'Surat': 5500, 'Indore': 950, 'Kochi': 7800}
print(Counter(c for c, _ in sales).most_common(1))   # [('Surat', 2)]

Comprehensions: list, dict, set and nested

Comprehensions read left to right: expression, then loop, then an optional filter.

prices = {"saree": 2400, "kurta": 899, "dupatta": 450}

discounted = {item: round(p * 0.9) for item, p in prices.items() if p > 500}
initials = {name[0] for name in prices}           # set comprehension
grid = [(r, c) for r in range(2) for c in range(3)]  # nested loops, outer first

Use zip() to walk two lists together and enumerate() when you need the position:

names = ["Asha", "Ravi"]
scores = [88, 74]
for rank, (name, score) in enumerate(zip(names, scores), start=1):
    print(rank, name, score)

Common mistakes

  • Using a mutable default argument such as def add(x, items=[]) — the same list is shared across calls. Use None and create the list inside.
  • Writing new = old and expecting a copy. Both names point to the same list.
  • Building huge comprehensions with three levels of nesting. If it needs a comment to explain, use a normal loop.
  • Forgetting that list.sort() returns None, so x = x.sort() wipes your data.

Practice

Given a list of (product, category, price) tuples for a textile shop, build a dict mapping each category to the name of its most expensive product, and a second dict with the average price per category rounded to 2 decimals.

B

Written by Bablu Kumar Jha

Founder, BeeProton AI · Mumbai, Maharashtra, India