Mundarija (21)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Counter — sanovchi lug'at
- 2.2. update — qo'shadi, almashtirmaydi
- 2.3. Multitoʻplam arifmetikasi
- 2.4. defaultdict — standart qiymatli lug'at
- 2.5. O'qish ham yozadi
- 2.6. __missing__ — mexanizm
- 2.7. Ichma-ich lug'at, pickle, json
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Counter asoslari
- Misol 2 — Counter arifmetikasi
- Misol 3 — defaultdict va uning tuzoqlari
- Misol 4 — Amaliy: onlayn do'kon buyurtmalari tahlili
- 5. To'g'ri va noto'g'ri tushunishlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8. Eng yaxshi amaliyotlar
- 9. Amaliy topshiriq
- Xulosa
15.6-dars: collections: Counter, defaultdict
15-QISM — STANDART KUTUBXONA · 6-dars
1. Kirish va motivatsiya
Dasturlashdagi eng ko'p uchraydigan ikki vazifa: sanash va guruhlash. "Qaysi mahsulot necha marta sotildi?", "har bir mijoz qaysi toifalardan xarid qildi?", "matnda qaysi so'z eng ko'p uchraydi?"
6-qismda bularni oddiy dict bilan yozdik:
sanoq = {}
for soz in sozlar:
if soz not in sanoq:
sanoq[soz] = 0
sanoq[soz] += 1Bu kod ishlaydi, lekin har safar bir xil andoza takrorlanadi va xato uchun joy qoladi. collections modulida buning uchun maxsus turlar bor:
Counter(sozlar).most_common(10) # sanash va eng ko'plari
guruhlar = defaultdict(list) # guruhlash
guruhlar[toifa].append(mahsulot)Real vaziyat. Analitika xizmatida sahifalar ko'rishini defaultdict(int) bilan sanashdi. Hisobot sahifasi "bu sahifa ko'rilganmi?" degan tekshiruvni sanoq[sahifa] > 0 bilan bajarardi. Bir necha kundan keyin xotira bir necha gigabaytga o'sdi: har bir tekshiruv — hatto mavjud bo'lmagan, botlar so'ragan manzillar uchun ham — lug'atga yangi kalit qo'shayotgan edi. defaultdict ning bitta xususiyatini bilmaslik qimmatga tushdi.
Bu darsda Counter va defaultdict ni chuqur o'rganamiz: ular aynan nima qiladi, qayerda dict dan farq qiladi va qanday jim tuzoqlari bor.
Bu darsda:
-
Counter: yaratish,most_common,total,update,elements -
Counterarifmetikasi:+,-,&,|,subtract, solishtirish -
Countervadict.updatefarqi, manfiy qiymatlar -
defaultdict:list,set,intbilan guruhlash - O'qish kalit qo'shadi —
in,getva xotira __missing__— mexanizmning o'zi- Ichma-ich lug'at,
picklevajson - Amaliy: onlayn do'kon buyurtmalari tahlili
2. Nazariya — chuqur tushuntirish
2.1. Counter — sanovchi lug'at
Counter — dict ning vorisi: kalit — element, qiymat — soni.
from collections import Counter
c = Counter("abrakadabra") # Counter({'a': 5, 'b': 2, 'r': 2, 'k': 1, 'd': 1})
Counter(["olma", "nok", "olma"]) # iterable dan
Counter({"olma": 3}) # lug'atdan
Counter(olma=3, nok=1) # kalit so'zlardan| Amal | Natija |
|---|---|
c["z"] (yo'q kalit) |
0 — xato emas, kalit qo'shilmaydi |
del c["z"] (yo'q kalit) |
Xato bermaydi |
c.most_common(n) |
Eng ko'p n ta; teng sonlarda — qo'shilish tartibida |
c.most_common()[-1] |
Eng kami |
c.total() |
Barcha sonlar yig'indisi (3.10+) |
c.elements() |
Har elementni soni marta; ≤ 0 lar tashlanadi |
2.2. update — qo'shadi, almashtirmaydi
dict.update |
Counter.update |
|
|---|---|---|
{"x": 1} ga {"x": 5} |
{"x": 5} — almashtiradi |
{"x": 6} — qo'shadi |
| Iterable bilan | Juftliklar kutiladi | Har elementni sanaydi |
Counter.subtract — ayiradi va manfiy qiymatlarni saqlaydi.
2.3. Multitoʻplam arifmetikasi
Counter ni multitoʻplam (bir element bir necha marta bo'la oladigan to'plam) sifatida ishlatish mumkin:
| Amal | Ma'nosi | Manfiy va nol |
|---|---|---|
a + b |
Sonlarni qo'shish | Natijadan tashlanadi |
a - b |
Ayirish | Natijadan tashlanadi |
a & b |
Minimum (kesishma) | Tashlanadi |
| `a | b` | Maksimum (birlashma) |
+a / -a |
Musbatlari / manfiylari (ishorasi almashtirilgan) | |
a.subtract(b) |
Ayirish joyida | Saqlanadi |
ombor = Counter(olma=3, nok=1)
buyurtma = Counter(olma=1, nok=2, anor=1)
buyurtma - ombor # Counter({'nok': 1, 'anor': 1}) — yetishmayotgani
ombor - buyurtma # Counter({'olma': 2}) — ortib qolgani
buyurtma <= ombor # False — bajarib bo'lmaydi (3.10+)Solishtirish (3.10+): == yo'q kalitlarni 0 deb hisoblaydi: Counter(a=1) == Counter(a=1, b=0) → True. <=, >= — har element bo'yicha.
2.4. defaultdict — standart qiymatli lug'at
from collections import defaultdict
guruhlar = defaultdict(list)
guruhlar["meva"].append("olma") # kalit yo'q → list() yaratiladi
sanoq = defaultdict(int) # int() == 0
toifalar = defaultdict(set) # takrorlarsiz guruhdefaultdict(fabrika) — fabrika argumentsiz chaqiriladigan har qanday narsa: list, set, int, dict, lambda: "noma'lum", o'z klassingiz.
| Tanlov | Qachon |
|---|---|
Counter |
Faqat sanash kerak — qulayroq va boy API |
defaultdict(int) |
Sanash + oddiy lug'at xulqi |
defaultdict(list) |
Guruhlash |
defaultdict(set) |
Takrorlarsiz guruhlash |
dict.setdefault(k, []) |
Bir martalik, oddiy dict kerak bo'lsa |
2.5. O'qish ham yozadi
defaultdict ning eng muhim xususiyati: yo'q kalitni d[k] bilan o'qish uni lug'atga qo'shadi.
| Amal | defaultdict |
Counter |
dict |
|---|---|---|---|
d[yoq] |
Qo'shadi, standart qiymat | 0, qo'shmaydi |
KeyError |
d.get(yoq) |
None, qo'shmaydi |
None, qo'shmaydi |
None |
yoq in d |
Tekshiradi, qo'shmaydi | Tekshiradi | Tekshiradi |
sanoq = defaultdict(int)
if sanoq["/admin.php"] > 0: ... # ❌ endi "/admin.php" lug'atda bor
if sanoq.get("/admin.php", 0) > 0: ... # ✅Oqibatlari: xotira o'sishi, len() noto'g'ri, JSON ga bo'sh yozuvlar tushishi, for tsikli ichida o'qish — RuntimeError: dictionary changed size during iteration.
Tashqariga (API, shablon, boshqa modul) defaultdict emas, dict(d) bering.
2.6. __missing__ — mexanizm
dict.__getitem__ kalitni topmasa, sinfda __missing__ bo'lsa uni chaqiradi. defaultdict va Counter aynan shu orqali ishlaydi:
| Sinf | __missing__ nima qiladi |
|---|---|
defaultdict |
fabrika() ni chaqiradi, saqlaydi, qaytaradi |
Counter |
0 qaytaradi, saqlamaydi |
| O'z sinfingiz | Istalgan xulq |
class Tarjima(dict):
def __missing__(self, kalit):
return f"[{kalit}]" # tarjima yo'q — kalitni ko'rsatish __missing__ faqat d[k] da ishlaydi — d.get(k) va k in d da emas.
default_factory atributi o'zgartirilishi mumkin; None qilinsa — oddiy KeyError.
2.7. Ichma-ich lug'at, pickle, json
daraxt = lambda: defaultdict(daraxt)
d = daraxt()
d["uz"]["toshkent"]["chilonzor"] = 5 # oraliq darajalar avtomatik| Holat | Natija |
|---|---|
json.dumps(Counter(...)) / json.dumps(defaultdict(...)) |
Oddiy JSON obyekt |
json.loads(...) |
Oddiy dict — turi qaytmaydi |
pickle + defaultdict(int) |
|
pickle + defaultdict(lambda: 0) |
PicklingError — lambda pickle bo'lmaydi |
multiprocessing orqali uzatish |
Xuddi shu cheklov (14.4-dars) |
pickle kerak bo'lsa — fabrika sifatida modul darajasidagi funksiya yoki klass.
3. Tez ma'lumotnoma
from collections import Counter, defaultdict
sanoq = Counter(sozlar)
sanoq.most_common(10); sanoq.total(); sanoq["yoq"] # 0
sanoq.update(yangi_sozlar) # qo'shadi
yetishmaydi = buyurtma - ombor; bajarsa_boladi = buyurtma <= ombor
guruh = defaultdict(list)
for x in malumot:
guruh[kalit(x)].append(x)
natija = dict(guruh) # tashqariga oddiy dict
guruh.get(k, []) # o'qish — qo'shmasdanQoidalar
sanash — Counter, guruhlash — defaultdict(list/set)
Counter.update qo'shadi, dict.update almashtiradi
Counter + - & | manfiy va nolni tashlaydi; subtract saqlaydi
defaultdict: d[k] o'qish kalit qo'shadi — tekshiruvda get / in
tashqariga dict(d)
pickle kerak — lambda emas, nomli funksiya4. Batafsil misollar
Misol 1 — Counter asoslari
"""Counter yaratish usullari; yo'q kalit; most_common va teng sonlar; total; update va dict.update farqi; elements; so'z chastotasi."""
import re
from collections import Counter
MATN = """Python — o'rganish oson til. Python bilan veb, ma'lumotlar tahlili va
avtomatlashtirish qilinadi. O'rganish uchun eng yaxshi yo'l — kod yozish, kod o'qish
va yana kod yozish."""
def main() -> None:
print("=== 1. Yaratish ===")
print(f" satrdan: {Counter('abrakadabra')}")
print(f" ro'yxatdan: {Counter(['olma', 'nok', 'olma'])}")
print(f" lug'atdan: {Counter({'olma': 3, 'nok': 1})}")
print(f" kalit so'zdan: {Counter(olma=3, nok=1)}")
print("\n=== 2. Yo'q kalit ===")
c = Counter("abrakadabra")
print(f" c['z'] = {c['z']}, 'z' in c: {'z' in c}, len(c) = {len(c)}")
del c["z"]
print(f" del c['z'] xato bermadi, len(c) = {len(c)}")
print("\n=== 3. most_common va total ===")
print(f" most_common(2): {c.most_common(2)}")
print(f" eng kami: {c.most_common()[-1]}")
print(f" total(): {c.total()} (satr uzunligi {len('abrakadabra')})")
print(f" teng sonlar — qo'shilish tartibida: {Counter('aab').most_common()} va {Counter('bba').most_common()}")
print("\n=== 4. ⚠️ update: Counter qo'shadi, dict almashtiradi ===")
oddiy = {"olma": 3}
oddiy.update({"olma": 5})
sanoq = Counter({"olma": 3})
sanoq.update({"olma": 5})
print(f" dict.update: {oddiy}")
print(f" Counter.update: {dict(sanoq)}")
sanoq.update(["nok", "olma", "nok"])
print(f" iterable bilan: {dict(sanoq)}")
print("\n=== 5. elements ===")
print(f" {sorted(Counter(a=2, b=1, c=0, d=-3).elements())} ← 0 va manfiylar tashlandi")
print("\n=== 6. So'z chastotasi ===")
sozlar = re.findall(r"[^\W\d_]+(?:['ʻ‘’][^\W\d_]+)*", MATN.lower())
chastota = Counter(sozlar)
print(f" so'zlar: {chastota.total()}, noyob: {len(chastota)}")
for soz, son in chastota.most_common(4):
print(f" {soz:10} {'█' * son} {son}")
print(f" bir marta uchraganlar: {sum(1 for s in chastota.values() if s == 1)}")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Yaratish ===
satrdan: Counter({'a': 5, 'b': 2, 'r': 2, 'k': 1, 'd': 1})
ro'yxatdan: Counter({'olma': 2, 'nok': 1})
lug'atdan: Counter({'olma': 3, 'nok': 1})
kalit so'zdan: Counter({'olma': 3, 'nok': 1})
=== 2. Yo'q kalit ===
c['z'] = 0, 'z' in c: False, len(c) = 5
del c['z'] xato bermadi, len(c) = 5
=== 3. most_common va total ===
most_common(2): [('a', 5), ('b', 2)]
eng kami: ('d', 1)
total(): 11 (satr uzunligi 11)
teng sonlar — qo'shilish tartibida: [('a', 2), ('b', 1)] va [('b', 2), ('a', 1)]
=== 4. ⚠️ update: Counter qo'shadi, dict almashtiradi ===
dict.update: {'olma': 5}
Counter.update: {'olma': 8}
iterable bilan: {'olma': 9, 'nok': 2}
=== 5. elements ===
['a', 'a', 'b'] ← 0 va manfiylar tashlandi
=== 6. So'z chastotasi ===
so'zlar: 25, noyob: 19
kod ███ 3
python ██ 2
o'rganish ██ 2
va ██ 2
bir marta uchraganlar: 14Nima ko'rsatdi: 2.1, 2.2-bo'limlar.
Misol 2 — Counter arifmetikasi
"""+ - & | amallari; subtract va manfiy qiymatlar; unar + va -; <= bilan solishtirish; ombor va buyurtma; anagrammalar."""
from collections import Counter
def main() -> None:
a = Counter(olma=3, nok=1)
b = Counter(olma=1, nok=2, anor=1)
print("=== 1. To'rt amal ===")
print(f" a = {dict(a)}, b = {dict(b)}")
print(f" a + b = {dict(a + b)}")
print(f" a - b = {dict(a - b)} ← nok manfiy bo'lardi, tashlandi")
print(f" b - a = {dict(b - a)}")
print(f" a & b = {dict(a & b)} (minimum)")
print(f" a | b = {dict(a | b)} (maksimum)")
print("\n=== 2. ⚠️ subtract manfiylarni saqlaydi ===")
qoldiq = Counter(a)
qoldiq.subtract(b)
print(f" subtract: {dict(qoldiq)}")
print(f" +qoldiq: {dict(+qoldiq)} (musbatlari)")
print(f" -qoldiq: {dict(-qoldiq)} (manfiylari, ishorasi almashgan)")
print("\n=== 3. Solishtirish (3.10+) ===")
print(f" Counter(a=1) == Counter(a=1, b=0): {Counter(a=1) == Counter(a=1, b=0)}")
print(f" Counter(a=1) <= Counter(a=2, b=1): {Counter(a=1) <= Counter(a=2, b=1)}")
print(f" Counter(a=3) <= Counter(a=2, b=5): {Counter(a=3) <= Counter(a=2, b=5)}")
print("\n=== 4. Ombor va buyurtmalar ===")
ombor = Counter(daftar=10, ruchka=25, qalam=4, chizgich=0)
buyurtmalar = [
("B-101", Counter(daftar=3, ruchka=5)),
("B-102", Counter(qalam=5, daftar=1)),
("B-103", Counter(chizgich=1)),
("B-104", Counter(ruchka=20, daftar=7)),
]
for raqam, buyurtma in buyurtmalar:
if buyurtma <= ombor:
ombor -= buyurtma
print(f" ✅ {raqam} bajarildi, omborda: {dict(sorted(ombor.items()))}")
else:
print(f" ❌ {raqam} yetishmaydi: {dict(buyurtma - ombor)}")
print(f" ⚠️ '-=' dan keyin 0 dona qolganlar ombordan yo'qoldi: {'chizgich' not in ombor and 'ruchka' not in ombor}")
print("\n=== 5. Anagrammalar va harflar yetadimi ===")
print(f" 'kitob' va 'botik' anagrammami: {Counter('kitob') == Counter('botik')}")
xat = Counter("salom dunyo".replace(" ", ""))
for soz in ("dunyo", "olma", "moll"):
print(f" gazeta harflaridan '{soz}' yig'iladimi: {Counter(soz) <= xat}")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. To'rt amal ===
a = {'olma': 3, 'nok': 1}, b = {'olma': 1, 'nok': 2, 'anor': 1}
a + b = {'olma': 4, 'nok': 3, 'anor': 1}
a - b = {'olma': 2} ← nok manfiy bo'lardi, tashlandi
b - a = {'nok': 1, 'anor': 1}
a & b = {'olma': 1, 'nok': 1} (minimum)
a | b = {'olma': 3, 'nok': 2, 'anor': 1} (maksimum)
=== 2. ⚠️ subtract manfiylarni saqlaydi ===
subtract: {'olma': 2, 'nok': -1, 'anor': -1}
+qoldiq: {'olma': 2} (musbatlari)
-qoldiq: {'nok': 1, 'anor': 1} (manfiylari, ishorasi almashgan)
=== 3. Solishtirish (3.10+) ===
Counter(a=1) == Counter(a=1, b=0): True
Counter(a=1) <= Counter(a=2, b=1): True
Counter(a=3) <= Counter(a=2, b=5): False
=== 4. Ombor va buyurtmalar ===
✅ B-101 bajarildi, omborda: {'daftar': 7, 'qalam': 4, 'ruchka': 20}
❌ B-102 yetishmaydi: {'qalam': 1}
❌ B-103 yetishmaydi: {'chizgich': 1}
✅ B-104 bajarildi, omborda: {'qalam': 4}
⚠️ '-=' dan keyin 0 dona qolganlar ombordan yo'qoldi: True
=== 5. Anagrammalar va harflar yetadimi ===
'kitob' va 'botik' anagrammami: True
gazeta harflaridan 'dunyo' yig'iladimi: True
gazeta harflaridan 'olma' yig'iladimi: True
gazeta harflaridan 'moll' yig'iladimi: FalseNima ko'rsatdi: 2.3-bo'lim.
Misol 3 — defaultdict va uning tuzoqlari
"""list/set/int bilan guruhlash; setdefault bilan solishtirish; o'qish kalit qo'shadi; get va in; tsikl ichida o'qish; default_factory; __missing__; ichma-ich daraxt; pickle."""
import json
import pickle
from collections import Counter, defaultdict
TALABALAR = [
("Aziz", "Python"), ("Malika", "Rust"), ("Aziz", "SQL"),
("Bek", "Python"), ("Malika", "Python"), ("Aziz", "Python"),
]
class Tarjima(dict):
def __missing__(self, kalit: str) -> str:
return f"[{kalit}]"
def nol() -> int:
return 0
def main() -> None:
print("=== 1. Guruhlash ===")
kurslar: defaultdict[str, list[str]] = defaultdict(list)
noyob: defaultdict[str, set[str]] = defaultdict(set)
for ism, kurs in TALABALAR:
kurslar[kurs].append(ism)
noyob[ism].add(kurs)
print(f" kurs → talabalar: {dict(kurslar)}")
print(f" talaba → kurslar: {({k: sorted(v) for k, v in noyob.items()})}")
setdefault_usul: dict[str, list[str]] = {}
for ism, kurs in TALABALAR:
setdefault_usul.setdefault(kurs, []).append(ism)
print(f" setdefault bilan bir xil: {setdefault_usul == kurslar}")
print("\n=== 2. ⚠️ O'qish kalit qo'shadi ===")
korishlar: defaultdict[str, int] = defaultdict(int)
for sahifa in ["/", "/kurs", "/", "/blog"]:
korishlar[sahifa] += 1
print(f" sanaldi: {dict(korishlar)}, len={len(korishlar)}")
botlar = ["/wp-admin", "/.env", "/admin.php", "/phpmyadmin"]
for manzil in botlar:
if korishlar[manzil] > 0:
pass
print(f" 4 ta tekshiruvdan keyin len={len(korishlar)}: {sorted(korishlar)}")
toza: defaultdict[str, int] = defaultdict(int, {"/": 2, "/kurs": 1})
for manzil in botlar:
if toza.get(manzil, 0) > 0 or manzil in toza:
pass
print(f" get va in bilan len={len(toza)} ← hech narsa qo'shilmadi")
c = Counter({"/": 2})
_ = c["/wp-admin"]
print(f" Counter o'qishda qo'shmaydi: len={len(c)}")
print("\n=== 3. ⚠️ Tsikl ichida o'qish ===")
ota: defaultdict[str, list[str]] = defaultdict(list, {"Aziz": ["Bek"], "Bek": []})
try:
for ism in ota:
for bola in ota[ism]:
_ = ota[bola + "ning bolasi"]
except RuntimeError as xato:
print(f" RuntimeError: {xato}")
print("\n=== 4. default_factory va __missing__ ===")
d: defaultdict[str, list[int]] = defaultdict(list, {"a": [1]})
print(f" default_factory: {d.default_factory.__name__}")
d.default_factory = None
try:
d["z"]
except KeyError:
print(" default_factory=None → KeyError")
tarjima = Tarjima(salom="hello")
print(f" Tarjima: {tarjima['salom']}, {tarjima['rahmat']}, get: {tarjima.get('rahmat')}, len={len(tarjima)}")
print("\n=== 5. Ichma-ich daraxt va JSON ===")
def daraxt() -> defaultdict:
return defaultdict(daraxt)
manzillar = daraxt()
manzillar["Toshkent"]["Chilonzor"]["9-kvartal"] = 120
manzillar["Toshkent"]["Yunusobod"]["4-kvartal"] = 85
manzillar["Samarqand"]["Markaz"]["Registon"] = 40
print(f" {json.dumps(manzillar, ensure_ascii=False)}")
qaytgan = json.loads(json.dumps(Counter("aab")))
print(f" JSON dan qaytgan tur: {type(qaytgan).__name__}")
print("\n=== 6. pickle ===")
for nom, obyekt in (("defaultdict(int)", defaultdict(int)),
("defaultdict(nol)", defaultdict(nol)),
("defaultdict(lambda: 0)", defaultdict(lambda: 0))):
try:
pickle.dumps(obyekt)
print(f" ✅ {nom}")
except (pickle.PicklingError, AttributeError) as xato:
print(f" ❌ {nom}: {type(xato).__name__}")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Guruhlash ===
kurs → talabalar: {'Python': ['Aziz', 'Bek', 'Malika', 'Aziz'], 'Rust': ['Malika'], 'SQL': ['Aziz']}
talaba → kurslar: {'Aziz': ['Python', 'SQL'], 'Malika': ['Python', 'Rust'], 'Bek': ['Python']}
setdefault bilan bir xil: True
=== 2. ⚠️ O'qish kalit qo'shadi ===
sanaldi: {'/': 2, '/kurs': 1, '/blog': 1}, len=3
4 ta tekshiruvdan keyin len=7: ['/', '/.env', '/admin.php', '/blog', '/kurs', '/phpmyadmin', '/wp-admin']
get va in bilan len=2 ← hech narsa qo'shilmadi
Counter o'qishda qo'shmaydi: len=1
=== 3. ⚠️ Tsikl ichida o'qish ===
RuntimeError: dictionary changed size during iteration
=== 4. default_factory va __missing__ ===
default_factory: list
default_factory=None → KeyError
Tarjima: hello, [rahmat], get: None, len=1
=== 5. Ichma-ich daraxt va JSON ===
{"Toshkent": {"Chilonzor": {"9-kvartal": 120}, "Yunusobod": {"4-kvartal": 85}}, "Samarqand": {"Markaz": {"Registon": 40}}}
JSON dan qaytgan tur: dict
=== 6. pickle ===
✅ defaultdict(int)
✅ defaultdict(nol)
❌ defaultdict(lambda: 0): PicklingErrorNima ko'rsatdi: 2.4–2.7-bo'limlar.
Misol 4 — Amaliy: onlayn do'kon buyurtmalari tahlili
Bitta hafta buyurtmalari asosida hisobot tuzamiz: eng ko'p sotilganlar, toifalar bo'yicha tushum, har mijozning toifalari, qaysi mahsulotlar birga olinadi va omborni to'ldirish uchun nima buyurtma qilish kerak. Pul butun so'mlarda saqlanadi — suzuvchi nuqta xatolarisiz.
"""Counter bilan sotuvlar va juftliklar; defaultdict bilan tushum va mijoz toifalari; ombor yetishmovchiligi; natijalarni o'zaro tekshirish."""
from collections import Counter, defaultdict
from itertools import combinations
NARXLAR = {"daftar": 8_000, "ruchka": 3_500, "sumka": 145_000, "kitob": 65_000, "kalkulyator": 120_000}
TOIFALAR = {"daftar": "kanselyariya", "ruchka": "kanselyariya", "sumka": "aksessuar",
"kitob": "kitoblar", "kalkulyator": "texnika"}
BUYURTMALAR = [
("Aziz", {"daftar": 5, "ruchka": 10}),
("Malika", {"kitob": 2, "daftar": 2}),
("Bek", {"sumka": 1, "daftar": 3, "ruchka": 2}),
("Aziz", {"kalkulyator": 1}),
("Nodira", {"daftar": 4, "ruchka": 4, "kitob": 1}),
("Malika", {"sumka": 1}),
("Bek", {"ruchka": 6}),
]
OMBOR = Counter(daftar=10, ruchka=30, sumka=1, kitob=5, kalkulyator=2)
ZAXIRA_MINIMUM = 5
def som(summa: int) -> str:
return f"{summa:,} so'm".replace(",", " ")
def main() -> None:
sotuv: Counter[str] = Counter()
tushum: defaultdict[str, int] = defaultdict(int)
mijoz_toifalari: defaultdict[str, set[str]] = defaultdict(set)
mijoz_summasi: Counter[str] = Counter()
juftliklar: Counter[tuple[str, str]] = Counter()
for mijoz, savat in BUYURTMALAR:
sotuv.update(savat)
for mahsulot, son in savat.items():
summa = NARXLAR[mahsulot] * son
tushum[TOIFALAR[mahsulot]] += summa
mijoz_summasi[mijoz] += summa
mijoz_toifalari[mijoz].add(TOIFALAR[mahsulot])
juftliklar.update(combinations(sorted(savat), 2))
print("=== 1. Eng ko'p sotilganlar ===")
for mahsulot, son in sotuv.most_common(3):
print(f" {mahsulot:12} {son:>3} dona")
print(f" jami dona: {sotuv.total()}")
print("\n=== 2. Toifalar bo'yicha tushum ===")
for toifa, summa in sorted(tushum.items(), key=lambda juft: -juft[1]):
print(f" {toifa:14} {som(summa):>13}")
jami = sum(tushum.values())
print(f" jami tushum: {som(jami)}")
print("\n=== 3. Mijozlar ===")
for mijoz, summa in mijoz_summasi.most_common():
print(f" {mijoz:7} {som(summa):>13} toifalar: {sorted(mijoz_toifalari[mijoz])}")
print("\n=== 4. Birga olinadigan mahsulotlar ===")
for (x, y), son in juftliklar.most_common(2):
print(f" {x} + {y}: {son} ta buyurtmada")
print("\n=== 5. Ombor ===")
qoldiq = Counter(OMBOR)
qoldiq.subtract(sotuv)
kamomad = -qoldiq
print(f" sotuvdan keyingi qoldiq: {dict(qoldiq)}")
print(f" omborda yetishmagan (oldindan buyurtma): {dict(kamomad)}")
maqsad = Counter({m: ZAXIRA_MINIMUM for m in NARXLAR})
toldirish = maqsad - +qoldiq
print(f" har biridan kamida {ZAXIRA_MINIMUM} ta bo'lishi uchun buyurtma: {dict(toldirish)}")
print("\n=== 6. O'zaro tekshiruvlar ===")
tekshir_jami = sum(NARXLAR[m] * s for m, s in sotuv.items())
print(f" toifalar tushumi = mahsulotlar tushumi: {jami == tekshir_jami}")
print(f" mijozlar summasi = jami tushum: {mijoz_summasi.total() == jami}")
print(f" sotilgan dona = buyurtmalardagi dona: {sotuv.total() == sum(sum(s.values()) for _, s in BUYURTMALAR)}")
print(f" har mahsulotda qoldiq + sotuv = boshlang'ich ombor: {all(qoldiq[m] + sotuv[m] == OMBOR[m] for m in NARXLAR)}")
print(f" ⚠️ OMBOR - sotuv da yetishmovchilik ko'rinmaydi: {dict(OMBOR - sotuv)}")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Eng ko'p sotilganlar ===
ruchka 22 dona
daftar 14 dona
kitob 3 dona
jami dona: 42
=== 2. Toifalar bo'yicha tushum ===
aksessuar 290 000 so'm
kitoblar 195 000 so'm
kanselyariya 189 000 so'm
texnika 120 000 so'm
jami tushum: 794 000 so'm
=== 3. Mijozlar ===
Malika 291 000 so'm toifalar: ['aksessuar', 'kanselyariya', 'kitoblar']
Bek 197 000 so'm toifalar: ['aksessuar', 'kanselyariya']
Aziz 195 000 so'm toifalar: ['kanselyariya', 'texnika']
Nodira 111 000 so'm toifalar: ['kanselyariya', 'kitoblar']
=== 4. Birga olinadigan mahsulotlar ===
daftar + ruchka: 3 ta buyurtmada
daftar + kitob: 2 ta buyurtmada
=== 5. Ombor ===
sotuvdan keyingi qoldiq: {'daftar': -4, 'ruchka': 8, 'sumka': -1, 'kitob': 2, 'kalkulyator': 1}
omborda yetishmagan (oldindan buyurtma): {'daftar': 4, 'sumka': 1}
har biridan kamida 5 ta bo'lishi uchun buyurtma: {'daftar': 5, 'sumka': 5, 'kitob': 3, 'kalkulyator': 4}
=== 6. O'zaro tekshiruvlar ===
toifalar tushumi = mahsulotlar tushumi: True
mijozlar summasi = jami tushum: True
sotilgan dona = buyurtmalardagi dona: True
har mahsulotda qoldiq + sotuv = boshlang'ich ombor: True
⚠️ OMBOR - sotuv da yetishmovchilik ko'rinmaydi: {'ruchka': 8, 'kitob': 2, 'kalkulyator': 1}Nima ko'rsatdi: 2.1–2.5-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
"Counter.update — dict.update bilan bir xil" |
Qo'shadi, almashtirmaydi |
"Counter da yo'q kalit KeyError" |
0 qaytaradi, qo'shmaydi |
"a - b manfiy natijalarni saqlaydi" |
Tashlaydi; subtract saqlaydi |
"defaultdict da d[k] faqat o'qiydi" |
Kalitni qo'shadi |
"defaultdict.get(k) standart qiymat beradi" |
None qaytaradi |
"__missing__ get da ham ishlaydi" |
Faqat d[k] da |
"json.loads Counter ni qaytaradi" |
Oddiy dict |
"Istalgan defaultdict pickle bo'ladi" |
lambda fabrika bilan — yo'q |
6. Keng tarqalgan xatolar va yechimlari
1. Tekshiruvda d[k]
if sanoq[manzil] > 0: ... # ❌ defaultdict — kalit qo'shiladi
if sanoq.get(manzil, 0) > 0: ... # ✅2. Counter bilan dict.update ni aralashtirish
jami = Counter(); jami.update(kunlik) # ✅ qo'shiladi
jami = {}; jami.update(kunlik) # ❌ almashtiriladi3. Manfiy qoldiqni - bilan yo'qotish
qoldiq = ombor - sotuv # ❌ yetishmovchilik ko'rinmaydi
qoldiq = Counter(ombor); qoldiq.subtract(sotuv) # ✅4. Qo'lda sanash
d = {}
for x in xs: d[x] = d.get(x, 0) + 1 # ⚠️ ishlaydi, lekin
d = Counter(xs) # ✅ qisqa va C da tezlashtirilgan5. defaultdict ni tashqariga berish
return guruhlar # ⚠️ chaqiruvchi o'qib kalit qo'shishi mumkin
return dict(guruhlar) # ✅6. Takrorlarsiz guruhda list
guruh = defaultdict(list) # ⚠️ takrorlar
guruh = defaultdict(set) # ✅7. pickle qilinadigan joyda lambda
defaultdict(lambda: "noma'lum") # ❌ multiprocessing, kesh
def nomalum(): return "noma'lum"
defaultdict(nomalum) # ✅8. most_common tartibiga tayanish
top = c.most_common(1)[0] # ⚠️ teng sonlarda — qo'shilish tartibi
top = max(c.items(), key=lambda kv: (kv[1], kv[0])) # ✅ aniq qoida7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 6-qism (o'tilgan):
dict,set, comprehension - 8.14-dars (o'tilgan): konteyner protokoli va dunder metodlar
- 15.7-dars:
deque,OrderedDict - 15.8–15.9-darslar:
itertools.groupby,combinations - 16-qism: fayllardan statistika yig'ish
- 24-qism:
pandasvalue_countsvagroupby— xuddi shu g'oyalar - 26.4-dars: scraping — sahifalardan so'z chastotalari
8. Eng yaxshi amaliyotlar
Sanash —
Counter, guruhlash —defaultdict(list)yokidefaultdict(set).defaultdictda tekshiruv —getyokiin.Tashqariga
dict(...)qaytaring.Yetishmovchilikni ko'rish kerak bo'lsa —
subtract.Teng sonlarda aniq tartib kerak bo'lsa — o'z saralash kalitingiz.
Pul — butun sonlarda (so'm yoki tiyin).
pickleqilinadigan joyda fabrika — nomli funksiya.Natijalarni o'zaro tekshiring — jami tushum har xil yo'l bilan bir xil chiqishi kerak.
9. Amaliy topshiriq
Vazifa 1: Natijani bashorat qiling
from collections import Counter, defaultdict
1. print(Counter("banana")["a"])
2. print(Counter("banana").most_common(1))
3. c = Counter("ab"); c["z"]; print(len(c))
4. d = defaultdict(int); d["z"]; print(len(d))
5. print(Counter(a=3) - Counter(a=5))
6. c = Counter(a=3); c.subtract(Counter(a=5)); print(c["a"])
7. c = Counter(a=1); c.update({"a": 2}); print(c["a"])
8. print(Counter(a=2, b=1) & Counter(a=1, b=3))
9. print(Counter("ab") == Counter("ba"))
10. d = defaultdict(list); print(d.get("x"))
11. print(sorted(Counter(x=2, y=0).elements()))
12. print(Counter("aaabb").total())Javoblar
3[('a', 3)]2—Countero'qishda qo'shmaydi1—defaultdictqo'shadiCounter()— manfiy tashlandi-23Counter({'a': 1, 'b': 1})TrueNone['x', 'x']5
Vazifa 2: Xatolarni tuzating
1. def korilganmi(sanoq, sahifa): # sanoq — defaultdict(int)
return sanoq[sahifa] > 0
2. def birlashtir(kunlik_hisobotlar):
jami = {}
for hisobot in kunlik_hisobotlar:
jami.update(hisobot)
return jami
3. def yetishmaydi(ombor, buyurtma):
qoldiq = ombor - buyurtma
return {k: v for k, v in qoldiq.items() if v < 0}
4. def guruhla(juftliklar):
g = {}
for kalit, qiymat in juftliklar:
g[kalit].append(qiymat)
return g
5. KESH = defaultdict(lambda: None) # multiprocessing orqali yuboriladiJavoblar
1. def korilganmi(sanoq, sahifa):
return sanoq.get(sahifa, 0) > 0
2. def birlashtir(kunlik_hisobotlar):
jami = Counter()
for hisobot in kunlik_hisobotlar:
jami.update(hisobot)
return dict(jami)
3. def yetishmaydi(ombor, buyurtma):
return dict(buyurtma - ombor) # yoki subtract + manfiylari
4. def guruhla(juftliklar):
g = defaultdict(list)
for kalit, qiymat in juftliklar:
g[kalit].append(qiymat)
return dict(g)
5. def yoq():
return None
KESH = defaultdict(yoq)Vazifa 3: Jurnal statistikasi
Veb-server jurnali (15.2-dars formati) uchun:
- Eng ko'p so'ralgan 10 ta manzil (
Counter) - Har IP → so'ragan manzillar to'plami (
defaultdict(set)) - Soatlar bo'yicha so'rovlar (
Countervadatetime) - 404 bergan manzillar va ularni so'ragan IP lar
- Hech bir natija lug'atida "sun'iy" kalit paydo bo'lmaganini testda isbotlang
Vazifa 4: Anagramma guruhlari
- O'zbekcha so'zlar ro'yxatidan anagramma guruhlarini toping (
defaultdict(list), kalit — saralangan harflar) - Xuddi shuni
Counterkaliti bilan qilishga urinib ko'ring — nega ishlamaydi? (frozenset(Counter(...).items())yechimi) - Eng katta guruhni toping
- Apostrofli so'zlarni (
o'rik) to'g'ri qayta ishlang
Vazifa 5: Ovoz berish tizimi
- Ovozlar ro'yxati —
Counter - Teng ovoz olganlarda — alifbo tartibida g'olib (aniq qoida)
- "Ikkinchi tur": eng kam ovoz olgan nomzodni chiqarib, uning saylovchilarining ikkinchi tanlovini qo'shing (reytingli ovoz)
- Har turdagi natijani chop eting
Vazifa 6: Retsept va xarid ro'yxati
- Har retsept —
Counter(ingredient → gramm) - Haftalik menyu:
Counterlar yig'indisi - Uydagi mahsulotlar —
Counter; xarid ro'yxati =menyu - uyda - Qaysi retseptlarni hozir tayyorlash mumkin (
retsept <= uyda) - Birliklarni (kg/g) me'yorlash
Vazifa 7: O'ylash
Counter — dict ning vorisi, shuning uchun Counter kutilgan joyga dict ham, dict kutilgan joyga Counter ham berilishi mumkin. Lekin update ning ma'nosi ular orasida teskari. Bu Liskov almashtirish tamoyilini (8-qism) buzadimi? Standart kutubxona nega bunday dizaynni tanlagan?
Javob
Qisqa javob: Ha, qat'iy ma'noda Counter.update Liskov tamoyilini buzadi: dict uchun yozilgan va update "almashtiradi" deb hisoblagan kod Counter bilan boshqacha natija beradi. Standart kutubxona bu yerda amaliy qulaylikni tanlagan: Counter ning asosiy vazifasi — sanash, va sanashda update ning tabiiy ma'nosi — qo'shish. Bu kelishuv hujjatlashtirilgan, lekin xavfli joy bo'lib qoladi.
1. Liskov almashtirish tamoyili
"Agar S — T ning vorisi bo'lsa, T kutilgan har joyda S ni ishlatish dastur to'g'riligini buzmasligi kerak."
2. Counter qayerda buzadi
| Metod | dict shartnomasi |
Counter |
|---|---|---|
update(m) |
Qiymatlar almashtiriladi | Qiymatlar qo'shiladi |
d[yoq] |
KeyError |
0 |
fromkeys |
Ishlaydi | NotImplementedError |
== |
Kalitlar to'plami bir xil bo'lishi kerak | 0 qiymatli kalitlar e'tiborsiz (3.10+) |
def sozlamani_yangila(sozlama: dict, yangi: dict) -> None:
sozlama.update(yangi) # "almashtiradi" deb yozilgan
s = Counter(port=8000)
sozlamani_yangila(s, {"port": 8080})
s["port"] # 16080 ❌3. Nega shunday tanlangan
- Tarix:
CounterPython 2.7/3.1 da (2009) boshqa tillardagi "bag/multiset" dan ilhomlangan; o'sha paytda merosdan foydalanish keng tarqalgan edi - Qulaylik:
dictning barcha metodlari (items,keys, iteratsiya, JSON) tekin keladi - Tezlik: C da tezlashtirilgan
dictustida qurilgan - Tabiiy ma'no: sanovchida "yangilash" — "qo'shish"
4. Muqobil dizaynlar
| Dizayn | Afzalligi | Kamchiligi |
|---|---|---|
Meros (Counter(dict)) — hozirgi |
Qulay, tez, dict API |
LSP buziladi |
Kompozitsiya (ichida dict) |
Shartnoma aniq | Ko'p kod, isinstance(c, dict) — False |
Mapping protokoli (13.5) |
Faqat o'qish shartnomasi | Yozish uchun alohida API |
Boshqa nom (add yoki count_all) |
Chalkashlik yo'q | update — tanish nom |
5. Amaliy xulosa
- Funksiya
dictqabul qilsa vaupdateqilsa —Counterbermang (yokidict(c)bering) - Tur annotatsiyasida o'qish uchun
Mapping[str, int]ishlating —updatechaqirilmasligini bildiradi - O'z sinflaringizda meros o'rniga kompozitsiya yoki protokollarni afzal ko'ring (8-qism, 13.5-dars)
- Standart kutubxona ham "ideal" OOP ga emas, amaliyotga moslashgan — hujjatni o'qish muhim
Nimani mustahkamlaydi: 2.1–2.7-bo'limlar.
Xulosa
Bu darsda sanash va guruhlash uchun maxsus lug'at turlarini o'rgandik.
Eng muhim uch fikr:
Counter— sanovchi va multitoʻplam. Yo'q kalit uchun0qaytaradi va uni qo'shmaydi,most_commoneng ko'plarini (teng sonlarda qo'shilish tartibida),total()yig'indini beradi.updateqo'shadi —dict.updatekabi almashtirmaydi. Arifmetika (+ - & |) manfiy va nol natijalarni tashlaydi,subtractesa saqlaydi;buyurtma <= omborbitta ifoda bilan "bajarib bo'ladimi?" savoliga javob beradi.defaultdict— guruhlashning asosi.defaultdict(list),defaultdict(set),defaultdict(int)bilanif kalit not in dandozasi yo'qoladi. Fabrika — argumentsiz chaqiriladigan istalgan narsa;picklekerak bo'lsalambdaemas, nomli funksiya.defaultdictda o'qish yozadi.d[kalit]yo'q kalitni qo'shadi — tekshiruvlarda xotira o'sadi,lennoto'g'ri bo'ladi, tsikl ichidaRuntimeErrorchiqadi. Tekshiruv uchungetyokiin, tashqariga esadict(d). Mexanizm —__missing__: u faqatd[k]da ishlaydi,getvainda emas.
Keyingi darsda collections ning qolgan turlarini ko'ramiz: deque — ikki tomonlama navbat, OrderedDict, ChainMap va namedtuple.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!