1.2.26 · D5 · HinglishIntroduction to Programming (Python)

Question bankNested data structures — list of dicts, dict of lists

2,342 words11 min read↑ Read in English

1.2.26 · D5 · Coding › Introduction to Programming (Python) › Nested data structures — list of dicts, dict of lists

Shuru karne se pehle, picture yahan seedhi bana lo taaki kuch bhi baad ke liye na chhodna pade. Dono structures same grid of cells store karte hain. Farq sirf itna hai ki pehle kaun sa axis slice karte ho:

Figure — Nested data structures — list of dicts, dict of lists

Figure dekho: left mein, ek List of Dicts (LoD) ko row cards ki stack ki tarah draw kiya gaya hai — har card ek dict hai {name, age, marks}. Right mein, ek Dict of Lists (DoL) ko side-by-side column strips ki tarah draw kiya gaya hai — har strip ek list hai. Coloured arrows follow karo: single cell "Ravi's marks = 73" LoD mein students[1]["marks"] par aur DoL mein students["marks"][1] par milti hai. Dono index paths cross over karte hain — wahi crossing transpose hai.


True or false — justify

Har item ek statement hai. True/false decide karo, phir reason do.

LoD aur DoL bilkul same information store kar sakte hain.
True. Ye dono transposes hain — same cells, bas rows-first vs columns-first organize kiye hue. Kisi bhi taraf se data lost nahi hota.
students[0]["name"] aur students["name"][0] hamesha same value return karte hain, structure chahe kuch bhi ho.
False. Har ek form sirf apne structure ke liye valid hai: LoD ke liye [i][c], DoL ke liye [c][i]. Doosra form error raise karta hai, isliye ye interchangeable nahi hain.
LoD mein outer container ka list hona matlab yeh hai ki pehle integer se index karna zaroori hai.
True. Ek list sirf integer (ya slice) indices accept karta hai; string key inner dict par use hoti hai, ek level aur neeche.
DoL mein har column-list ki same length honi chahiye.
True (well-formed data ke liye). Row tab hi exist karta hai jab har column mein index par ek element ho; unequal lengths ka matlab hai kuch "rows" mein fields missing hain aur structure toot gaya hai.
dol = lod2dol(lod) ke baad back = dol2lod(dol) karne par, back == lod True hai lekin back is lod False hai.
True. == contents compare karta hai (equal cells → equal), isliye pass ho jaata hai; is identity compare karta hai (memory mein same object), aur back ek freshly built list hai, isliye is fail hota hai. Round-tripping value preserve karta hai, identity nahi.
LoD→DoL→LoD round-tripping tab bhi data preserve karta hai jab kuch rows mein keys missing hon.
False. Ragged rows ke saath LoD→DoL step missing cells ko ek default (jaise None) se fill karta hai, isliye rebuilt LoD mein waise keys aa jaati hain jo original mein nahi thi — ab == bhi fail ho jaata hai, sirf is nahi.
Jab rows bahut zyada hon toh DoL equivalent LoD se kam memory use karta hai.
True (typically), aur reason yeh hai: 3 fields aur rows ke saath, LoD field-name strings baar store karta hai (har row-dict mein ek baar); DoL unhe sirf baar store karta hai, dict keys ke roop mein. ke liye woh ~3000 vs ~3 key-string references hain — values dono mein same cost karti hain.
DoL mein naya record utni aasani se append kar sakte ho jitna LoD mein.
False. LoD ek single step mein ek self-contained dict append karta hai. DoL mein har column-list mein alag se append karna padta hai aur unhe aligned bhi rakhna padta hai.
for s in students: LoD mein rows iterate karta hai aur DoL mein columns.
True. Ek list iterate karne par uske elements (row-dicts) milte hain; ek dict iterate karne par uske keys (column names) milte hain — yeh ek classic surprise hai agar bhool jaao ki outer container badal gaya.
Modern Python (3.7+) mein DoL ki keys iterate karne par random order mein aati hain.
False. Dicts insertion order preserve karte hain, isliye iterate karne par keys usi order mein milti hain jisme columns define kiye gaye the — reliable aur repeatable, arbitrary nahi.

Spot the error

Har line code describe karti hai. Batao kya toot ta hai aur kyun.

students["name"] jahan students ek list of dicts hai.
Ek list ko string se index nahi kar sakte, isliye yeh TypeError raise karta hai. Tumne LoD par DoL access mix kar di — students[0]["name"] use karo.
students[0] jahan students ek dict of lists hai jisme string keys hain.
KeyError: 0 — dict mein koi key 0 nahi hai; uski keys field names hain jaise "name". Pehle students["name"] use karo.
dol = dict.fromkeys(["name","age"], []) phir dol["name"].append("Asha") — object IDs trace karo.
id(dol["name"]) == id(dol["age"]) True hai: dono keys fromkeys dwara bani ek hi list ko point kar rahi hain, isliye append ke baad dono mein ["Asha"] dikhega. Minimal proof:
>>> dol = dict.fromkeys(["name","age"], [])
>>> dol["name"].append("Asha")
>>> dol{'name': ['Asha'], 'age': ['Asha']}. Fix karo {c: [] for c in cols} se, jahan har [] apna fresh object hai jiska apna id hai — dekho Mutable vs Immutable.
{k: [row[k] for row in lod] for k in lod[0]} jab ek row {"name":"Ravi"} ho (koi "marks" nahi).
Us row par KeyError: "marks" aayega. Comprehension yeh maan leti hai ki har row lod[0] ki keys share karti hai. Default ke liye row.get(k) use karo.
for s in students: students.remove(s) se LoD clear karna.
Iterate karte hue remove karne se indices shift ho jaate hain, isliye loop elements skip karta hai — kabhi poora clear nahi hoga. Iske bajaay naya list banao: students = [s for s in students if s["marks"] >= 40], sirf wahi rows rakho jinka condition sahi ho (yahan, pass marks) instead of in-place delete karne ke.
avg = sum(students["marks"]) ek list of dicts par.
students["marks"] pehle hi TypeError se fail ho jaata hai (list ko string se index kiya). Column math tabhi directly kaam karta hai jab column already built ho, ya DoL mein seedha.
n = len(students) ko dict of lists ki row count ke roop mein use karna.
DoL par len(students) columns count karta hai (keys ki sankhya), rows nahi. Row count hai len(students[any_key]) — ek column ki length.
row["age"] += 5 andar for row in students jahan students ek DoL hai.
row ek string key hai jaise "age", dict nahi, isliye row["age"] TypeError raise karta hai. Dict iterate karne par keys milti hain — kisi cell ko touch karne ke liye students["age"][i] use karo.

Why questions

Reason answer karo, sirf ek fact nahi.

DoL column average compute karne mein kyun jeet ta hai?
Column already ek flat list hai, isliye sum(col)/len(col) seedha run hota hai — records mein se gather karne ke liye pehle comprehension ki zaroorat nahi.
LoD poora record add ya delete karne mein kyun jeet ta hai?
Har record ek single self-contained dict hai, isliye append (add) ya list-filtering (remove) sirf ek object ko touch karta hai, har column ko nahi.
Dono forms ke beech indices order kyun swap ho jaata hai ([i][c] vs [c][i])?
Kyunki ye structures transposes hain: jo bhi container outer hota hai, usse pehle access karte hain. LoD mein row-phir-field; DoL mein field-phir-row.
LoD JSON from an API ke saath naturally kyun match karta hai?
JSON typically ek array of objects bhejta hai — ek list jahan har object ek record hai named fields ke saath, jo directly Python list of dicts se map hota hai.
for x in students se DoL iterate karna beginners ko kyun surprise karta hai?
Dict iterate karne par uski keys (column names) milti hain, rows nahi. LoD se aane par (jo rows yield karta hai) same syntax silently kuch alag matlab rakhta hai.
Shared-list bug sirf dict.fromkeys(cols, []) ke saath kyun appear karta hai, dict comprehension ke saath nahi?
fromkeys [] ko ek baar evaluate karta hai aur har key ko us ek object ki taraf point karta hai; comprehension {c: [] for c in cols} har iteration par [] fresh run karta hai, independent lists deta hai.
LoD→DoL conversion mein keys carefully collect kyun karni padti hain jab rows alag ho sakti hain?
Agar sirf lod[0] ki keys par trust karo toh baaki rows ke paas jo fields hain woh miss ho jaate hain; safe key set hai {k for row in lod for k in row} sab rows par.
Pandas DataFrame ko "turbocharged DoL" kyun kaha jaata hai?
DataFrame har column ko ek contiguous array ke roop mein store karta hai (column-first, jaise DoL), isliye column operations fast hain — lekin saath hi rows ko bhi conveniently slice karne deta hai, dono strengths combine karke.

Edge cases

Boundary aur degenerate inputs — woh scenarios jo log bhool jaate hain.

Ek empty LoD []: lod[0] kya karta hai, aur uski keys kaise milti hain?
lod[0] IndexError raise karta hai (koi row 0 nahi) aur koi keys padhne ko hain hi nahi — empty LoD ka koi schema nahi hota. lod[0] touch karne se pehle if lod: se guard karo.
Ek empty DoL {}: isme kitni rows hain?
Undefined — koi column nahi hai toh measure karne ke liye koi column hi nahi. len(dol) 0 hai (zero columns), aur row count tab tak unknowable hai jab tak kam se kam ek key exist na kare.
LoD par students[-1] vs DoL par students[-1] — har ek ka kya matlab hai?
LoD par outer container ek list hai, isliye -1 last row hai (valid, students[len-1]). DoL par outer container ek dict hai, isliye -1 ko key ki tarah treat kiya jaata hai; jab tak literally -1 naam ki key exist na kare, KeyError raise hoga. Negative indexing sirf list layer par kaam karti hai.
students[1:3] (ek slice) LoD par vs DoL par — kaun sa kaam karta hai?
LoD par kaam karta hai: list ko slice karne par rows 1 aur 2 ek chhote LoD ke roop mein milti hain. DoL par TypeError raise hota hai — dicts ko start:stop se slice nahi kar sakte. DoL mein rows slice karne ke liye har column slice karna padega: {c: students[c][1:3] for c in students}.
Ek DoL jahan columns ki alag lengths hain ("name" len 3, "age" len 2): kya row 2 valid hai?
Row 2 sirf "name" ke liye exist karta hai; dol["age"][2] poochh ne par IndexError aayega. Structure malformed hai — har column ka row count same hona chahiye.
Ek LoD jahan row 0 mein extra keys hain jo baaki rows mein nahi hain: kya {k: [row[k] ...] for k in lod[0]} kaam karta hai?
Nahi — yeh row 0 ki keys iterate karta hai, isliye baad ki rows mein jo key nahi hai usse padhne ki koshish karta hai, KeyError raise ho jaata hai. .get(k) ya full key set use karo.
Sirf ek record wala LoD [{"a":1}]: kya yeh valid LoD hai, aur iska DoL?
Haan. Ek row bilkul theek hai; iska DoL hai {"a":[1]} — har column ek length-1 list ban jaati hai. Transpose relationship phir bhi hold karta hai.
Sirf ek column wala DoL {"a":[1,2,3]}: iska LoD form kya hai?
[{"a":1},{"a":2},{"a":3}] — teen rows, har ek ek single-field dict. Row count single column ki length se aaya.
Rows mein duplicate field values (do students ka naam "Asha") — kya koi bhi structure toot ta hai?
Koi nahi toot ta; dono duplicate values allow karte hain. Sirf dict keys unique honi chahiye, aur keys field names hain, values nahi.
Ek field value jo khud ek list hai (jaise LoD mein "marks":[88,73] har student ke liye): kya access badal jaata hai?
Nahi — students[0]["marks"] phir bhi woh inner list return karta hai; bas ek level aur neeche index karna padta hai (students[0]["marks"][1]) kisi element tak pahunchne ke liye. Nesting cleanly compose hoti hai.

Connections

  • Lists — integer-indexed container jo LoD ke outer aur DoL ke inner mein hai
  • Dictionaries — key→value lookup jo dono ko power deta hai
  • List Comprehensions — transpose engine aur ragged-key traps
  • JSON and APIs — kyun list-of-dicts common wire format hai
  • Pandas DataFrame — column-first storage, DoL ko production tak le jaana
  • Loops and Iteration — kyun dict vs list iterate karna surprise karta hai
  • Mutable vs Immutable — shared-inner-list bug ki root cause