</>SyntaxPilot
Notes › Data Analytics with Python › Episode 5

Python for Data 2: Lists, Tuples, Dictionaries and Sets

▶ Watch the videoTry the code in the compilerAll Data Analytics with Python notes

These are the notes for Data Analytics with Python, episode 5. You will learn Python's four built-in data structures (ways to organise many values together): lists, tuples, dictionaries and sets. You'll index and slice lists, use list methods (append, extend, pop, sort), learn the difference between mutable and immutable, look things up by key in a dict, remove duplicates with a set, test membership with in, and see how a list of dicts is really a table. Every term is defined the first time it appears and collected in the Glossary. Every program below was run for real (Python 3.13); outputs are unedited.

The problem: one variable per day

Ramesh wants his weekly total and average. With one variable per day:

mon = 320
tue = 280
wed = 410
thu = 300
fri = 350
sat = 390
sun = 450
total = mon + tue + wed + thu + fri + sat + sun
print(total)
print(total / 7)
2500
357.14285714285717

It works for a week. For a year it needs 365 variables and a 365-name total line, and the hand-typed 7 must change whenever a day is added. Miss one and the answer is silently wrong.

Lists

A train A Python list Meaning
One train, one name, many coaches in order List One variable holding many values in order, inside [ ], separated by commas
Coaches numbered from the engine, starting at 0 Index The position of a value, counted from 0
Attaching or removing coaches Mutable Can be changed after it is created
week = [320, 280, 410, 300, 350, 390, 450]
print(week)
print(type(week))
print(len(week))
print(sum(week))
print(sum(week) / len(week))
print(max(week), min(week))
[320, 280, 410, 300, 350, 390, 450]
<class 'list'>
7
2500
357.14285714285717
450 280

len() (length: how many items), sum(), max() and min() are built-in functions that work on any list. sum(week) / len(week) has no hand-typed 7, so it stays right when days are added. Each value in a list is called an element or item.

Indexing and slicing

Indexing means picking one value by its position: week[0]. A negative index counts from the end: -1 is the last value. A slice week[a:b] is a new, smaller list from index a up to, but not including, b.

week   = [320, 280, 410, 300, 350, 390, 450]
index:     0    1    2    3    4    5    6
negative: -7   -6   -5   -4   -3   -2   -1
week = [320, 280, 410, 300, 350, 390, 450]
print(week[0])
print(week[6])
print(week[-1])
print(week[0:5])
print(week[5:])
print(week[7])
320
450
450
[320, 280, 410, 300, 350]
[390, 450]
Traceback (most recent call last):
  File "main.py", line 7, in <module>
    print(week[7])
          ~~~~^^^
IndexError: list index out of range

List methods

A method is a function that belongs to a value and is called with a dot: week.append(330).

Method / operation What it does
week[1] = 290 Replace the value at index 1 (item assignment)
week.append(x) Add one value at the end
week.extend([a, b]) Add every value from another list at the end
week.insert(i, x) Insert a value at position i
week.pop() Remove the last value and return it (pop(i) removes index i)
week.sort() Sort the list in place (changes it, returns None)
sorted(week) Built-in: return a new sorted list, original untouched
week.index(x) The index of the first x
week = [320, 280, 410, 300, 350, 390, 450]
week[1] = 290          # fix a typo
week.append(330)       # next Monday
print(week)
week.extend([310, 295])
print(week, len(week))
last = week.pop()
print(last, week)
week.sort()
print(week)
[320, 290, 410, 300, 350, 390, 450, 330]
[320, 290, 410, 300, 350, 390, 450, 330, 310, 295] 10
295 [320, 290, 410, 300, 350, 390, 450, 330, 310]
[290, 300, 310, 320, 330, 350, 390, 410, 450]

The sort trap

week = [320, 280, 410]
week = week.sort()
print(week)
print(sum(week))
None
Traceback (most recent call last):
  File "main.py", line 4, in <module>
    print(sum(week))
          ~~~^^^^^^
TypeError: 'NoneType' object is not iterable

sort() changes the list in place and returns None (nothing), so week = week.sort() replaced the list with None. Iterable means "something you can go through one item at a time"; None isn't. Fix: call week.sort() on its own, or use sorted():

week = [320, 280, 410]
print(sorted(week))
print(week)
print(sorted(week, reverse=True))
[280, 320, 410]
[320, 280, 410]
[410, 320, 280]

Tuples: records that must not change

A tuple holds values in order, written in round brackets ( ), and can never be changed once made. Something that can't change after it's created is immutable.

record = ("Mon", "sunny", 320)
print(record[0], record[2])
print(type(record))
record[2] = 330
Mon 320
<class 'tuple'>
Traceback (most recent call last):
  File "main.py", line 4, in <module>
    record[2] = 330
    ~~~~~~^^^
TypeError: 'tuple' object does not support item assignment
Mutable (can change) Immutable (can't change)
list, dict, set int, float, str, bool, None, tuple

Use a tuple for a fixed record (day, weather, cups) and a list for a collection that grows. A one-item tuple needs a comma: (320,).

Dictionaries: look up by name

Two parallel lists (lists that must stay in step) drift apart silently:

items = ["chai", "samosa", "bun maska"]
prices = [12, 15, 25]
print(prices[items.index("samosa")])
items.insert(0, "coffee")   # new item added at the top...
print(prices[items.index("samosa")])   # ...prices forgot
15
25

The samosa now "costs" Rs 25. Nothing warned us.

Menu card Python Meaning
Item name Key The name you look up; keys are unique
Its price Value What the key points to
The whole card dict (dictionary) Key-value pairs in { }, key: value

A key and its value form a key-value pair; they travel together, so they can't slide apart. Since Python 3.7, a dict keeps its pairs in the order you added them (the docs: "Dict preserves insertion order").

menu = {"chai": 12, "samosa": 15, "bun maska": 25}
print(menu["samosa"])
menu["coffee"] = 20       # add
menu["chai"] = 15         # update
print(menu)
print(len(menu))
print(menu.keys())
print(menu.values())
print(menu.items())
print(menu.get("vada pav", 0))
print(menu["vada pav"])
15
{'chai': 15, 'samosa': 15, 'bun maska': 25, 'coffee': 20}
4
dict_keys(['chai', 'samosa', 'bun maska', 'coffee'])
dict_values([15, 15, 25, 20])
dict_items([('chai', 15), ('samosa', 15), ('bun maska', 25), ('coffee', 20)])
0
Traceback (most recent call last):
  File "main.py", line 11, in <module>
    print(menu["vada pav"])
          ~~~~^^^^^^^^^^^^
KeyError: 'vada pav'

Sets: unique values

visits = ["Asha", "Ravi", "Asha", "Meena", "Ravi", "Asha", "Joseph"]
print(len(visits))
regulars = set(visits)
print(regulars)
print(len(regulars))
print("Meena" in regulars, "Kiran" in regulars)
regulars.add("Kiran")
print(len(regulars))
print(regulars[0])
7
{'Meena', 'Joseph', 'Ravi', 'Asha'}
4
True False
5
Traceback (most recent call last):
  File "main.py", line 9, in <module>
    print(regulars[0])
          ~~~~~~~~^^^
TypeError: 'set' object is not subscriptable

Membership with in

x in collection asks "is x inside?" and gives a bool. Membership = being a member of a collection.

week = [320, 280, 410, 300, 350, 390, 450]
menu = {"chai": 12, "samosa": 15}
print(450 in week)
print("samosa" in menu)
print(12 in menu)
print("Mon" in "Monday")
True
True
False
True

in on a dict checks the keys, not the values (12 in menu.values() would be True). On a string it checks for a piece of text. not in is the opposite.

Which structure when?

Structure Syntax Ordered? Changeable? Duplicates? Use it for
list [320, 280] Yes Yes (mutable) Yes A growing collection: daily sales
tuple ("Mon", 320) Yes No (immutable) Yes A fixed record
dict {"chai": 12} Yes (insertion order) Yes Keys: no Lookup by name
set {"Asha", "Ravi"} No Yes No Unique values, fast in

Nested data: a list of dicts is a table

Nested data means data structures inside each other.

week = [
    {"day": "Mon", "weather": "sunny", "cups": 320},
    {"day": "Tue", "weather": "rainy", "cups": 280},
    {"day": "Wed", "weather": "sunny", "cups": 410},
]
print(len(week))
print(week[1])
print(week[1]["cups"])
week[1]["cups"] = 290
print(week[1])
3
{'day': 'Tue', 'weather': 'rainy', 'cups': 280}
280
{'day': 'Tue', 'weather': 'rainy', 'cups': 290}

The outer list holds the rows; each dict is one row; the shared keys are the columns. Read week[1]["cups"] left to right: row 1, then column cups. This is exactly how JSON data looks, and pandas turns it into a table with pd.DataFrame(week).

Mini project: weekly summary

days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
cups = [320, 280, 410, 300, 350, 390, 450]
rainy = {"Tue", "Thu"}
best = max(cups)
best_day = days[cups.index(best)]
weekend = cups[5:]
print(f"Total: {sum(cups)} cups")
print(f"Average: {sum(cups) / len(cups):.1f} cups a day")
print(f"Best day: {best_day} ({best} cups)")
print(f"Weekend share: {sum(weekend) / sum(cups):.0%}")
print(f"Was Tue rainy? {'Tue' in rainy}")
Total: 2500 cups
Average: 357.1 cups a day
Best day: Sun (450 cups)
Weekend share: 34%
Was Tue rainy? True

:.0% formats a fraction (0.336) as a percentage with no decimals (34%).

Common mistakes

Code Real error Why Fix
week[7] (7 items) IndexError: list index out of range Indexes run 0 to len - 1 week[6] or week[-1]
week = week.sort() None, then TypeError: 'NoneType' object is not iterable sort() returns None week.sort() or sorted(week)
record[2] = 330 (tuple) TypeError: 'tuple' object does not support item assignment Tuples are immutable Build a new tuple, or use a list
menu["vada pav"] KeyError: 'vada pav' The key doesn't exist menu.get("vada pav", 0) or check in first
regulars[0] (set) TypeError: 'set' object is not subscriptable Sets have no order Loop over it, or sorted(regulars)[0]
Parallel lists (no error: wrong price) Lists slid out of step Use a dict
12 in menu (no error: False) in checks dict keys 12 in menu.values()

Practice

1. sales = [320, 280, 410, 300, 350, 390, 450]. Write the slice for Tuesday to Thursday, and for the last three days, two ways.

Solution

sales[1:4] → [280, 410, 300]. Last three: sales[4:] or sales[-3:] → [350, 390, 450].

2. Build a dict of 5 friends and their cities. Add one friend, change one city, and print each pair.

Solution
cities = {"Asha": "Pune", "Ravi": "Delhi", "Meena": "Chennai", "Joseph": "Kochi", "Kiran": "Jaipur"}
cities["Arjun"] = "Lucknow"
cities["Ravi"] = "Noida"
print(cities.items())

3. Count the unique words in "chai and samosa and chai again".

Solution

words = "chai and samosa and chai again".split() gives a list of 6 words; len(set(words)) is 4 (chai, and, samosa, again). The split() method breaks text into a list at spaces.

4. Which structure would you use for: (a) daily temperatures for a year, (b) a customer's (id, name, city) record, (c) product → stock count, (d) the PIN codes you deliver to?

Solution

(a) list, (b) tuple, (c) dict, (d) set.

5. Given the list-of-dicts week above, print Wednesday's weather, and change Monday's cups to 330.

Solution

print(week[2]["weather"]) → sunny; week[0]["cups"] = 330.

Quick quiz

sales = [320, 280, 410, 300, 350]
print(sales[1:3], sales[-2])

A. [320, 280, 410] 350 B. [280, 410] 300 C. [280, 410, 300] 300 D. [280, 410] 350

Answer

B. The slice starts at index 1 and stops before index 3: [280, 410]. -2 is the second from the end: 300.

Interview questions

  1. List vs tuple? Both are ordered; a list is mutable, a tuple is immutable (safer for fixed records, usable as dict keys).
  2. When would you use a set? To remove duplicates, count distinct values, or test membership quickly.
  3. How do you avoid a KeyError? Use d.get(key, default) or check key in d first.
  4. sort() vs sorted()? list.sort() sorts in place and returns None; sorted() returns a new list and works on any iterable.
  5. What does week[-1] mean? The last element; negative indexes count from the end.
  6. How would you represent a small table in plain Python? A list of dicts (one dict per row, keys as columns), which is also how JSON records look.

Glossary

Term Meaning Example
Data structure A way to organise many values together list, dict
List Ordered, changeable collection in [ ] [320, 280]
Element / item One value inside a collection 280
Index The position of an element, from 0 week[0]
Negative index Position counted from the end, from -1 week[-1]
Indexing Picking one value by position week[2]
Slicing Taking a sub-list a:b (b excluded) week[0:5]
Off-by-one error Going one position too far (or short) week[7] for 7 items
len() Number of items len(week) → 7
sum(), max(), min() Total, largest, smallest max(week)
Built-in function A function Python always has, no import needed len, sorted
Method A function attached to a value, called with a dot week.append(330)
append Add one item at the end week.append(330)
extend Add all items of another list week.extend([310, 295])
pop Remove and return an item (last by default) week.pop()
sort Sort a list in place; returns None week.sort()
sorted() Return a new sorted list sorted(week, reverse=True)
In place Changing the original object instead of making a new one week.sort()
Iterable Something you can go through one item at a time lists, strings, dicts
Mutable Can be changed after creation list, dict, set
Immutable Can't be changed after creation tuple, str, int
Tuple Ordered, unchangeable collection in ( ) ("Mon", 320)
Item assignment Replacing a value at an index or key week[1] = 290
Parallel lists Separate lists that must stay in step items, prices
Dictionary (dict) Key-value pairs in { } {"chai": 12}
Key The unique name you look up in a dict "chai"
Value What a key points to 12
Key-value pair One key with its value "chai": 12
keys() / values() / items() All keys / all values / all pairs menu.items()
get() Look up a key with a default if missing menu.get("x", 0)
KeyError Error for a missing dict key menu["vada pav"]
Set Unordered collection of unique values {"Asha", "Ravi"}
Duplicate A value that appears more than once "Asha" ×3
Subscriptable Can be used with [ ] lists yes, sets no
Membership (in) Test whether a value is inside a collection "Asha" in regulars
Nested data Data structures inside each other a list of dicts
JSON A text format for data that looks like dicts and lists {"day": "Mon"}
split() Break text into a list of words "a b".split() → ['a', 'b']

Summary

← Episode 4Python for Data 1: Variables, Data Types, Operators and f-stringsEpisode 6 →Python for Data 3: if/elif/else, for and while Loops, and Comprehensions