1.2.33 · D2 · HinglishIntroduction to Programming (Python)

Visual walkthroughBuilt-in functions — map, filter, zip, enumerate, sorted, reversed, min, max, sum, any, all

3,512 words16 min read↑ Read in English

1.2.33 · D2 · Coding › Introduction to Programming (Python) › Built-in functions — map, filter, zip, enumerate, sorted, re

Prerequisites jinpar hum rely karte hain lekin zaroorat padne par rebuild karenge: Lambda functions, Iterators and generators, Truthiness in Python. Yeh parent topic ka picture-first companion hai.


Step 1 — Conveyor belt: ek iterable actually kya hota hai

KYA HAI. Kisi bhi function se pehle, humein woh cheez chahiye jo sab khaate hain: ek iterable. Iterable woh kuch bhi hai jise tum ek item ek time par walk through kar sako — ek list [7, 3, 9], ek string "abc", ek range. Ek conveyor belt imagine karo jis par boxes hain. Har box mein ek value hoti hai.

WHY yahan se shuru karein. Is page ka har function (map, filter, zip, sorted, sum, …) is baat se define hota hai ki woh boxes ki belt ke saath kya karta hai. Agar tum belt nahi dekhte, toh functions magic lagte hain. Agar dekhte ho, toh obvious hain.

PICTURE. Figure dekho: ek white belt teen amber boxes carry kar rahi hai jinpar 7, 3, 9 likha hai. Arrow travel ki direction dikhata hai — left start hai, right wahan hai jahan ek hungry function items pull karega.


Step 2 — map: ek station jo har box ko repaint karta hai

KYA HAI. Hamara raw data hai scores = [40, 75, 88, 33, 90]. Maano yeh 100 mein se hain lekin hum inhe 1.0 mein se fractions chahte hain. Hum har ek ko 100 se divide karte hain. map(f, xs) ek worker ko station par rakhta hai: jaise-jaise har box aage badhta hai, worker f apply karta hai aur transformed box ko wapas belt par rakhta hai.

  • x — is waqt station par box ke andar ki value.
  • x/100 — woh repainted value jo station se nikalta hai.
  • Puri cheez ek naya belt return karti hai, same length, har box transformed.

WHY map aur for-loop nahi? Loop tumse likhaata hai ki indices mein kaise peeche daudo. map kehta hai kya chahiye: "yeh rule har ek par apply karo." Ek station, ek rule — kuch galat karne ki jagah nahi.

WHY lazy? Worker kuch nahi karta jab tak downstream koi box nahi kheenchta (next(...) nahi chalata — upar wala mechanism box dekho). list(map(...)) "abhi sab kuch pull karo" wala command hai. Figure dekho: doosri belt faint draw ki gayi hai (abhi compute nahi hui) jab tak puller nahi aata.

PICTURE. Top belt: raw boxes 40, 75, 88, 33, 90. Station (cyan) mein rule x/100 hai. Bottom belt: 0.40, 0.75, 0.88, 0.33, 0.90.


Step 3 — filter: ek trapdoor wala station

KYA HAI. Ab hum sirf passing scores ki parwah karte hain (≥ 50, yani Step 2 ke baad x >= 0.5). filter(pred, xs) ek worker rakhta hai jo har box par haan/na ka sawaal check karta hai. Agar jawab truthy hai, box aage jaata hai; agar falsy hai, trapdoor khulta hai aur box gir jaata hai.

  • pred(x) True/False return karta hai (ya kuch bhi truthy/falsy).
  • True → box rehta hai. False → box gir jaata hai.

WHY filter aur map nahi? map boxes ko badalta hai lekin count maintain rakhta hai. filter sirf survivors ka count maintain karta hai — yeh belt ki length badalta hai, box contents kabhi nahi. Yeh do alag kaam hain, isliye do alag stations.

Edge case — filter(None, xs). Agar function ki jagah None pass karo, toh filter har box ki apni truthiness use karta hai. Toh 0, '', [], None sab trapdoor se gir jaate hain. Hum yeh isliye cover kar rahe hain kyunki parent note ne ise flag kiya tha.

PICTURE. Incoming belt 0.40, 0.75, 0.88, 0.33, 0.90. Boxes 0.40 aur 0.33 (dono < 0.5) ek red trapdoor se gir jaate hain. Surviving belt: 0.75, 0.88, 0.90.


Step 4 — zip aur enumerate: do belts side by side chalana

KYA HAI. Hamare paas sirf scores nahi hain — hamare paas names bhi hain: names = ['Ann','Bo','Cy','Di','Ed']. Har score ko uske student se joda rakha jaaye, isliye hum dono belts ko ek zip station se guzaarte hain, jo har belt se ek box uthata hai aur unhe ek pair mein staple kar deta hai.

  • Har output box ek tuple (name, score) hai — belt A ka i-wa box belt B ke i-we se joda gaya.
  • zip shortest belt par ruk jaata hai, toh koi khaali haath lekar nahi baikhta.

enumerate = counter belt ke saath zip. Agar names ki jagah positions chahiye, toh enumerate(xs, start=0) ek auto-counting belt 0, 1, 2, … tumhari belt par staple karta hai. Yeh literally zip(counter, xs) hai:

for i, v in enumerate(['a', 'b', 'c'], start=1):
    print(i, v)      # 1 a / 2 b / 3 c

WHY filter se pehle pair karein? Taaki jab trapdoor ek failing score giraye, toh woh student ka naam bhi saath le jaaye — pair ek box ki tarah travel karta hai. Agar hum sirf scores filter karte toh hum track kho dete ki kaun pass hua.

PICTURE. Do parallel belts (names cyan mein, scores amber mein) ek stapler station ko feed karti hain; output belt paired boxes ('Ann',0.40) … ('Ed',0.90) carry karti hai. Ek chhota inset dikhata hai enumerate 0,1,2 counter belt staple karta hua names ki jagah.


Step 5 — Stations chain karna: belt ek line hai

KYA HAI. Real pipelines stations chain karte hain. Pairing (zip) phir selecting (filter) milke yeh banta hai:

paired  = zip(names, map(lambda x: x / 100, scores))
passing = filter(lambda pair: pair[1] >= 0.5, paired)

Ise inside-out padho (belt bahar ki taraf flow karti hai): scores map mein jaate hain, scaled belt names ke saath zip hoti hai, paired belt filter ko feed karti hai, survivor belt bahar aati hai. Yahan pair[1] har (name, score) box ka score half hai.

WHY inside-out? Kyunki har inner call outer ka argument hai, isliye innermost call belt ka sabse pehla station hai. (Agar nesting se aankhein thak jaayein, List comprehensions wahi pipeline left-to-right likhte hain — same belt, friendlier syntax.)

WHY abhi bhi kuch compute nahi hua? Har station yahan (map, zip, filter) lazy hai. Belt poori tarah assemble ho gayi hai lekin frozen hai — koi next(...) call nahi hua, isliye koi box nahi hila. Woh tabhi hilega jab ek reducer (agla step) pull karna shuru kare.

PICTURE. Series mein teen stations ke saath ek lambi belt: x/100, phir zip stapler (names upar se join karti hain), phir trapdoor pair[1] >= 0.5. Output end ek "?" se cap hai — puller abhi aaya nahi.


Step 6 — Reducers belt ko EK jawab mein badal dete hain

KYA HAI. Ab ek reducer (Step 4 mein define kiya) ant mein khada hota hai aur belt drain karta hai. Hum do summaries chahte hain: average passing score aur top passer. Lekin ek belt single-use hoti hai — ek reducer drain kare toh woh khaali! Isliye hum pehle survivors ko list mein materialize karte hain, phir jitni baar chahein reduce karte hain.

passing = list(passing)                 # freeze: [('Bo',0.75),('Cy',0.88),('Ed',0.90)]
scores_only = [p[1] for p in passing]
average = sum(scores_only) / len(scores_only)   # 2.53 / 3 = 0.8433...
top = max(passing, key=lambda p: p[1])          # ('Ed', 0.90)
  • sum(scores_only) — accumulator 0 se shuru hota hai, har box add karta hai: 0 + 0.75 + 0.88 + 0.90 = 2.53.
  • len(scores_only) — kitne survive kiye = 3.
  • average = 2.53 / 3 = 0.8433…
  • max(passing, key=…) — score half p[1] se compare karta hai; sabse bada ('Ed', 0.90) hai. min se swap karo sabse kamzor passer milega, ('Bo', 0.75).

WHY list mein materialize karein? Kyunki hum belt kai baar drain karte hain (sum, len, max). Ek lazy belt pehle drain ke baad khaali ho jaati hai. list(...) boxes ko ek reusable shelf par freeze kar deta hai. (Parent ka "reusing a consumed iterator" mistake dekho.)

WHY sum 0 se shuru hota hai? Accumulator ko ek starting value chahiye. 0 + ka identity hai (ise add karne se kuch nahi badalta), isliye yeh safe seed hai. Yahi reason hai kyun sum(['a','b']) crash karta hai: woh 0 + 'a' try karta hai — ek number aur ek string.

PICTURE. Survivor belt of pairs do hoppers feed karti hai: ek amber "SUM" hopper jiska dial 0 → 0.75 → 1.63 → 2.53 climb karta hai (side mein count = 3avg = 0.843), aur ek cyan "MAX" hopper jo sirf tallest box ('Ed', 0.90) rakhta hai.


Step 7 — Degenerate belts: agar kuch survive na kare toh?

KYA HAI. Maano har score fail ho: scores = [10, 20, 30]. Scaling aur filter(pair[1] >= 0.5) ke baad, zero boxes survive karte hain. Ab reducers ek khaali belt par alag behave karte hain:

Reducer [] par Result Kyun
sum([]) 0 identity seed
len([]) 0 count karne ko kuch nahi
any([]) False OR ka identity — koi True nahi
all([]) True AND ka identity — koi counter-example nahi (vacuous truth)
min([]) / max([]) ValueError kuch nahi ka koi extreme element nahi hota

Toh average = sum / len0 / 0ZeroDivisionError, aur max(passing) khaali belt par → ValueError. Dono ko guard karna padega.

WHY yeh dikhayein? Kyunki ek pipeline jo poori belt par kaam krti hai, khaali belt par crash kar sakti hai — woh case jo beginners kabhi test nahi karte. Tum dono ko guard karo:

average = sum(scores_only) / len(scores_only) if passing else 0.0
top = max(passing, key=lambda p: p[1]) if passing else None

Yahan if passing belt ki apni truthiness use karta hai: ek non-empty list truthy hai, ek khaali list [] falsy hai.

any/all ka view. "Kya kisi ne pass kiya?" → any(p[1] >= 0.5 for p in belt); khaali par → False. "Kya sabne pass kiya?" → all(...); khaali par → True, vacuously. min/max ke saath asymmetry note karo: any/all ke khaali input par safe defaults hain, lekin min/max raise karte hain (jab tak default= pass na karo).

PICTURE. Left: ek khaali belt SUM hopper tak pahunchi — dial 0 par atki, counter 0 par, red "÷ 0 ✗" warning. Middle: ek MAX hopper jisme khaali belt aa rahi hai, "ValueError ✗" dikh raha hai. Right: do gauges — any([]) = False, all([]) = True.


Step 8 — Belt ko order karna: sorted aur reversed

KYA HAI. Kabhi-kabhi hum reduce nahi karte — hum reorder karte hain. sorted(xs, key=…, reverse=…) poori belt padh leta hai, phir order mein boxes ke saath ek brand-new belt bichha deta hai. Yeh original ko kabhi touch nahi karta.

deta hai [('Ed',0.90), ('Cy',0.88), ('Bo',0.75)].

  • key — ek optional worker jo batata hai ki kis cheez se compare karein (yahan score p[1]). Koi key nahi → boxes directly compare karein.
  • reverse=True — final order ulta karo.
  • Ties apna original order maintain karte hain — Python ka sort stable hai.

WHY ek naya belt (in-place nahi)? Taaki tumhara original data survive kare. .sort() belt ko in-place mutate karta aur None return karta; sorted tumhe fresh belt deta hai aur source akela chodta hai. Contrast: reversed(seq) usi belt ki lazy back-to-front walk hai — koi naya belt nahi, aur ise known length wali sequence chahiye (list/tuple/range/str).

PICTURE. Top: original belt (untouched, "original" marked). Bottom: ek alag naya belt descending score order mein sorted(key=…, reverse=True) se bana. Ek dashed arrow read-then-rebuild dikhata hai; original unchanged highlight hai.


Ek-picture summary

Final figure poori line compress karta hai: do raw belts (names, scores) → map (scale) → zip (staple) → filter (trapdoor) → list (freeze) → reducers (sum/len → average, max → top passer) aur, ek taraf, sorted/reversed ek fresh ordered belt bichha rahe hain. Figure ko ek box ki story ki tarah padho: ek raw score scale hota hai, apne naam se jodha jaata hai, trapdoor par check hota hai, shelf par freeze hota hai, aur aakhir mein average mein count hota hai ya max ke taur par crown pata hai. Lazy stations (map, zip, filter) ek box tab tak nahi halaate jab tak reducer pull na kare; reducers woh akele stations hain jo belt khatam karte hain.

Yeh corrected one-liner hai (koi keywords-as-names nahi, sab variables defined hain):

passing = list(filter(lambda p: p[1] >= 0.5,
                      zip(names, map(lambda x: x / 100, scores))))
average = sum(p[1] for p in passing) / len(passing) if passing else 0.0
Recall Feynman retelling — kisi dost ko batao

Conveyor belts imagine karo jisme numbers ke boxes hain.

  • map ek station par painter hai: jo bhi box aage badhta hai, usi rule par apply hota hai (÷100). Boxes ki same sankhya, naye colours. Yeh do belts ek saath bhi chala sakta hai aur unhe box-for-box add kar sakta hai.
  • zip ek stapler hai: yeh names belt se ek box aur scores belt se ek box leta hai aur unhe ek pair-box mein staple karta hai, taaki score apne student se kabhi alag na ho. enumerate wahi stapler hai lekin doosri belt ek automatic 0, 1, 2, … counter hai.
  • filter ek trapdoor wala station hai: kya pair sawaal pass karta hai (score ≥ 0.5)? toh aage jaata hai. Fail karta hai? poora pair gir jaata hai. Values untouched, bas unki sankhya kam.
  • Painter, stapler, aur trapdoor lazy hain — yeh literally kuch nahi karte jab tak far end par koi na kahe "agla box, please" (woh next(...) hai, jo for, list, aur sum sab internally kehte hain). Belt assemble karna free hai; chalana pull ki cost hai.
  • Ek reducer ant mein khada rehta hai aur belt ko ek jawab mein drain karta hai: sum ek dial mein jo 0 se shuru hota hai, len count karta hai, max/min tallest/shortest box rakhte hain, any/all ek True/False mein ghul jaate hain. Kyunki belt single-use hai, tum survivors ko ek list mein freeze karo agar unhe ek se zyada baar drain karna ho.
  • Agar koi box survive na kare, belt khaali hai: sum 0 deta hai, len 0 deta hai, aur 0÷0 crash karta hai; max/min bhi crash karte hain (kuch nahi ka koi extreme nahi hota). Lekin any([]) False hai aur all([]) True. Khaali case guard karo.
  • sorted belt padh ke ek fresh ordered belt bichhaata hai, original akela chodta hai; reversed bas usi belt ko ulta chalta hai.
Recall

len(map(f, xs)) error kyun raise karta hai? ::: map ek lazy iterator return karta hai jismein koi __len__ nahi; materialize karne ke baad len(list(map(f, xs))) karo. map(f, xs) mein, kya boxes ki sankhya badlati hai? ::: Nahi — map length preserve karta hai; ek box in, ek box out. zip(a, b) kya produce karta hai aur kahan ruk jaata hai? ::: Tuples (a[i], b[i]) ka ek iterator; yeh shortest input par ruk jaata hai. enumerate ka zip se kya relation hai? ::: enumerate(xs)zip(counter, xs) — yeh har item par ek auto-counting index staple karta hai. filter(pred, xs) mein, kya surviving box values badlati hain? ::: Nahi — filter sirf rakhta ya girta hai; values untouched rehti hain. Kai baar reduce karne se pehle survivors ko list(...) mein kyun wrap karein? ::: Lazy belt single-use hoti hai; pehla reducer ise drain kar deta hai, isliye baad ke reducers khaali belt dekhenge. list reusable boxes freeze karta hai. Passing scores [0.75, 0.88, 0.90] ka average kya hai? ::: 2.53 / 3 = 0.8433… max(passing, key=lambda p: p[1]) yahan kya return karta hai? ::: ('Ed', 0.90) — sabse bade score wala pair. Khaali belt par sum, any, all, aur max kya karte hain? ::: sum([])=0, any([])=False, all([])=True, lekin max([]) ValueError raise karta hai. sorted original belt ke saath kya karta hai? ::: Kuch nahi — yeh ek naya ordered list return karta hai aur source unchanged chodta hai.