Exercises — Nested data structures — list of dicts, dict of lists
1.2.26 · D4· Coding › Introduction to Programming (Python) › Nested data structures — list of dicts, dict of lists
Climb karne se pehle, ek baar woh ek law yaad karo parent parent note se jis par neeche sab kuch tikaa hai:
Poore document mein, "LoD" = List of dicts, "DoL" = Dict of lists.
Neeche ki picture woh transpose law ko concrete bana ke dikhati hai: wahi dataset do baar draw kiya gaya hai, ek baar horizontal row-cards ki tarah (LoD) aur ek baar vertical column-lists ki tarah (DoL). Plum-shaded cell trace karo — yeh Ravi ka score hai, left pe [1][score] se aur right pe [score][1] se reach hota hai. Dekho ki do coordinates literally apni jagah swap karte hain jab tumhari nazar purple arrow cross karti hai: wahi swap poori idea hai, aur is page ke har exercise us ka ek variation hai.

Hamaara running dataset (shape yaad karo, numbers nahin):
# List of dicts (LoD) — one dict = one row
people_lod = [
{"name": "Asha", "age": 20, "score": 88},
{"name": "Ravi", "age": 22, "score": 73},
{"name": "Meera", "age": 21, "score": 95},
]
# Dict of lists (DoL) — one list = one column
people_dol = {
"name": ["Asha", "Ravi", "Meera"],
"age": [20, 22, 21],
"score": [88, 73, 95],
}Do Python facts jinka hum baar baar use karte hain — inhe ek baar yahan recap karo taaki page se bahar kabhi na jaana pade:
Recall Recap:
comprehension kya hota hai (aur hum ise kyun use karte hain)
Ek list comprehension [f(x) for x in seq] shorthand hai "ek nayi list banao f ko seq
ke har x pe run karke." Yeh 3-line loop replace karta hai:
out = []
for x in seq:
out.append(f(x))Hum ise yahan kyun use karte hain: LoD mein, ek column ki values alag-alag dicts mein
bikhri hoti hain. Ek comprehension unhe gather karne ka compact tarika hai —
[row["score"] for row in people_lod] har row pe chalta hai aur uska score ek flat list mein
kheench laata hai. Sirf kuch rows rakhne ke liye end mein if cond add karo.
Poori treatment List Comprehensions mein.
Recall Recap:
mutable objects identity share karte hain (kyun ek edit do names pe dikh sakta hai) Lists aur dicts mutable hain — tum unka content in place change kar sakte ho. Importantly, ek variable list ki copy nahin rakhta; woh memory mein ek list object ka reference (pointer) rakhta hai. Agar do names usi list ki taraf point kar rahein hain, toh ek ke through edit karna doosre se bhi dikhta hai:
a = []
b = a # b points to the SAME list as a
a.append(1)
b # [1] — b changed too, they are one objectYahan kyun matter karta hai: kai exercises mein galti se bahut saare dict keys ek hi list share kar lete hain, toh ek mein append karna sab mein append karta dikh jaata hai. Fix yeh hai ki hamesha ek fresh list banao. Poori treatment Mutable vs Immutable mein.
Level 1 — Recognition
Goal: dono shapes ko alag karo aur bina code run kiye ek single cell padho.
L1.1 — Yeh kaun si shape hai?
Har snippet dekho aur bolo LoD ya DoL, aur outer container type ka naam batao.
A = [{"x": 1}, {"x": 2}]
B = {"x": [1, 2], "y": [3, 4]}Recall Solution L1.1
Aek LoD hai: outer[...]hai (ek list), har element ek dict hai → list of dicts.Bek DoL hai: outer{...}hai (ek dict), har value ek list hai → dict of lists. Giveaway hamesha sabse baahri bracket hoti hai:[⇒ list ⇒ LoD,{⇒ dict ⇒ DoL.
L1.2 — Ek cell padho (bina code ke)
Upar diye people_lod se, people_lod[1]["name"] kya evaluate karta hai?
Recall Solution L1.2
Pehle outer peel karo. people_lod[1] doosri row hai (index 0 se start hoti hai):
{"name": "Ravi", "age": 22, "score": 73}. Phir ["name"] us dict ka name field padhta hai.
Answer: "Ravi".
L1.3 — Same cell, doosri shape
people_dol mein, usi cell (row 1, field name) ke liye expression likho.
Recall Solution L1.3
Transpose law apply karo — pehle key, phir integer index:
people_dol["name"][1] → "Ravi". LoD ke people_lod[1]["name"] se compare karo:
dono coordinates ka order literally swap ho gaya.
Level 2 — Application
Goal: standard operations run karo — column math, updates, filtering.
L2.1 — Average score, dono shapes se
Teen logon ka average score compute karo, ek baar people_lod se aur ek baar people_dol se.
Recall Solution L2.1
LoD (scores alag-alag dicts mein bikhre hain → pehle comprehension se gather karo):
total = sum(p["score"] for p in people_lod) # 88 + 73 + 95 = 256
avg = total / len(people_lod) # 256 / 3DoL (column already flat list hai → directly sum karo):
avg = sum(people_dol["score"]) / len(people_dol["score"]) # 256 / 3Dono dete hain. Yahi reason hai ki DoL column math mein jeet jaata hai:
koi gathering step nahin. p["score"] for p in ... engine ke liye List Comprehensions
dekho.
L2.2 — Ek field update karo
Har structure mein Ravi ka score 5 se badhao.
Recall Solution L2.2
LoD — pehle row dhundhni padegi (naam se search), phir uski field edit karo:
for p in people_lod:
if p["name"] == "Ravi":
p["score"] += 5 # 73 → 78DoL — agar position already pata hai (row index 1), directly edit karo:
people_dol["score"][1] += 5 # 73 → 78Dono mein nayi value: 78. (Yeh in place mutate karta hai — Mutable vs Immutable dekho.)
L2.3 — Rows filter karo
people_lod se sirf un logon ka nayi LoD banao jinka score >= 85 ho. Result ki name list do.
Recall Solution L2.3
top = [p for p in people_lod if p["score"] >= 85]
names = [p["name"] for p in top] # ["Asha", "Meera"]Asha (88) aur Meera (95) pass karte hain; Ravi (73) fail karta hai. Result names: ["Asha", "Meera"].
Humne in place delete karne ki jagah nayi list banai — zyada safe hai (L5 trap dekho).
Level 3 — Analysis
Goal: reason karo ki kaun si task kaun si shape prefer karti hai, aur errors predict karo.
L3.1 — Error predict karo
people_lod["name"] run karne par kya hoga (note: LoD hai, DoL nahin)?
Recall Solution L3.1
people_lod ek list hai. List ko sirf integer (ya slice) se index kiya ja sakta hai,
kabhi string se nahin. Python TypeError raise karta hai: "list indices must be integers
or slices, not str."
Fix transpose law hai: pehle integer → people_lod[0]["name"].
L3.2 — Kaun si shape, aur kyun?
Har task ke liye, behtar structure ka naam batao aur ek-line reason do.
- Ek bilkul nayi person record append karo.
- Sabka maximum
agedhundo. - 1 million rows store karo jo sab 3 keys share karte hain, kam se kam memory mein.
Recall Solution L3.2
- LoD — ek record ek self-contained dict hota hai jise tum list mein sirf
.append(...)kar dete ho. - DoL —
agecolumn already ek flat list hai, tohmax(people_dol["age"])seedha kaam karta hai. (Yahaanmax = 22.) - DoL — key strings (
"name","age","score") dict keys ke roop mein ek baar store hote hain, ek million dicts mein baar baar nahin. LoD mein key strings ek million baar store honge. Yahi shape Pandas DataFrame hood ke andar use karta hai.
L3.3 — Matching rows ki count
people_lod use karke, kitne log strictly 20 se bade hain? Expression dikhao.
Recall Solution L3.3
count = sum(1 for p in people_lod if p["age"] > 20) # Ravi(22), Meera(21) → 2sum(1 for ...) un rows ko count karta hai jo pass karte hain. Answer: 2. (Asha exactly 20
hai, toh > 20 use exclude karta hai.)
Level 4 — Synthesis
Goal: ek shape se doosri shape banao, aur nayi structures construct karo.
L4.1 — LoD → DoL (transpose)
Is LoD ko haath se DoL mein convert karo, phir ek line mein.
lod = [{"name": "Asha", "score": 88},
{"name": "Ravi", "score": 73}]Recall Solution L4.1
Haath se: har key ke liye chalo, us key ki value ko order mein har row se collect karo.
namecolumn:["Asha", "Ravi"]scorecolumn:[88, 73]One-liner:
dol = {k: [row[k] for row in lod] for k in lod[0]}
# {"name": ["Asha", "Ravi"], "score": [88, 73]}Outer comprehension keys pe iterate karta hai (pehli row lod[0] se liye, kyunki sab rows
keys share karte hain). Inner comprehension har row pe chalta hai us key ki values gather karne
ke liye. Yeh literally swap perform karta hai.
L4.2 — DoL → LoD (reverse transpose)
Waapis convert karo:
dol = {"name": ["Asha", "Ravi"], "score": [88, 73]}Recall Solution L4.2
keys = list(dol) # ["name", "score"]
n = len(dol[keys[0]]) # rows = length of any column = 2
lod = [{k: dol[k][i] for k in keys} for i in range(n)]
# [{"name":"Asha","score":88}, {"name":"Ravi","score":73}]list(dol) ["name", "score"] kyun deta hai: Python mein ek dict ko iterate karna —
ya use list(...) mein wrap karna — uski keys pe chalta hai, values pe nahin. Toh
list(dol) insertion order mein column names ki ek plain list hai. (Values ke liye tum
dol.values() maangoge; pairs ke liye dol.items().) Hume yahan column names chahiye, toh
list(dol) bilkul sahi hai.
Phir row index i ko 0 se n-1 tak loop karo. Har i ke liye, har column ka i-wa
element padh ke ek dict banao. Woh hai dol[k][i] — DoL coordinate — lod[i][k] mein
assemble kiya gaya.
L4.3 — Ek dict of lists mein group karo
Transactions ki ek LoD di gayi hai, ek DoL banao jo har city ko us city ke amounts ki list
se map kare.
tx = [{"city": "Pune", "amt": 100},
{"city": "Delhi", "amt": 40},
{"city": "Pune", "amt": 60}]Recall Solution L4.3
groups = {}
for t in tx:
groups.setdefault(t["city"], []).append(t["amt"])
# {"Pune": [100, 60], "Delhi": [40]}setdefault(key, []) key ke liye existing list return karta hai, ya pehli baar us key ko
dekhne par ek fresh empty list create karta hai, phir hum .append karte hain. Result:
Pune → [100, 60], Delhi → [40]. Har city ka sum: Pune = 160, Delhi = 40.
Level 5 — Mastery
Goal: corner cases mein survive karo — missing keys, mutation-while-iterating, degenerate inputs.
L5.1 — Ragged rows (missing keys)
Is LoD mein ek row ka score key missing hai. Ek aisa DoL transpose likho jo crash na kare,
missing cells ko None se fill kare.
lod = [{"name": "Asha", "score": 88},
{"name": "Ravi"}] # no "score"!Recall Solution L5.1
Pehle saari rows mein se poora key set collect karo (sirf lod[0] par bharosa mat karo,
woh kuch keys miss kar sakta hai jo kuch rows mein hain aur kuch mein nahin). Phir .get(k)
use karo jo key absent hone par None return karta hai.
keys = {k for row in lod for k in row} # {"name", "score"}
dol = {k: [row.get(k) for row in lod] for k in keys}
# {"name": ["Asha", "Ravi"], "score": [88, None]}score column [88, None] hai — Ravi ki missing cell KeyError raise karne ki jagah None
ban gayi. Yeh exactly wahi shape hai jo JSON and APIs tab deta hai jab records inconsistent
hote hain.
L5.2 — Rows safely delete karo
people_lod se un sabko remove karo jinka score < 80 hai. Explain karo ki naive in-place loop
kyun galat hai, phir correct code do aur surviving names batao.
Recall Solution L5.2
Galat (iterate karte waqt mutate karna):
for p in people_lod:
if p["score"] < 80:
people_lod.remove(p) # BUG: shifts indices mid-loop → skips elementsJab tum ek item remove karte ho, uske baad sab kuch left shift ho jaata hai, lekin loop ka internal counter phir bhi aage badhta hai — toh woh element jo freed slot mein slide ho gaya woh skip ho jaata hai. Correct (nayi list banao):
people_lod = [p for p in people_lod if p["score"] >= 80]
# keeps Asha(88), Meera(95); drops Ravi(73)Surviving names: ["Asha", "Meera"]. Kyun nayi list mein filter karna safe idiom hai, yeh
Loops and Iteration mein dekho.
L5.3 — Degenerate inputs
Har ke liye result (ya error) predict karo, aur safe version do.
- Ek empty LoD
[]ka average score. - Ek empty LoD
[]ka DoL mein transpose.
Recall Solution L5.3
sum(p["score"] for p in []) / len([])→ sum0hai,len0hai →ZeroDivisionError. Safe:avg = total / n if n else 0(yaNone). Divide-by-zero ko explicitly guard karo.{k: [...] for k in lod[0]}→ empty list parlod[0]IndexErrorhai (koi pehli row nahin). Safe:dol = {} if not lod else {k: [row.get(k) for row in lod] for k in lod[0]}. Empty dataset mein koi column nahin hota, toh empty DoL{}sahi answer hai.
Score yourself
Connections
- Lists — LoD ka outer container, DoL ka inner
- Dictionaries — key→value lookups jo dono shapes ko power dete hain
- List Comprehensions — yahan har transpose ke peeche ka engine
- JSON and APIs — jahaan se ragged real-world LoDs aate hain
- Pandas DataFrame — ek fast dict-of-lists jisme column ops built in hain
- Loops and Iteration — safe traversal aur mutate-while-iterate trap
- Mutable vs Immutable — kyun shared-list bug bolta hai