aidoc.uz

2-qism · Ma'lumot tuzilmalari va funksiyalar·06-bob

Lug'atlar, to'plamlar va collections moduli

dict va set qanday ishlaydi (hash jadval), hashlanish nima, eng muhim metodlar va idiomalar, Counter, defaultdict, deque, namedtuple — va qachon qaysi tuzilmani tanlash.

Agar ro'yxat Python'ning eng ko'p ishlatiladigan tuzilmasi bo'lsa, lug'at (dict) — eng muhimi. Python'ning o'zi lug'atlar ustiga qurilgan: modul atributlari, klass atributlari, funksiya argumentlari (**kwargs) — hammasi ichkarida lug'at. JSON — lug'at. API so'rov va javoblari — lug'at. Model konfiguratsiyasi — lug'at. Bu bob — Python'ni haqiqatan tushunishning yarim yo'li.

▶ Video dars· Corey Schafer· 9:59· ingliz tilida
Python Tutorial for Beginners 5: Dictionaries - Working with Key-Value Pairs

Lug'atlar bilan ishlash: kalitlar, get, update, aylanish. collections moduli (Counter, defaultdict, deque) — bobning 7-bo'limida.

YouTube'da ochish ↗

1. Lug'at asoslari#

Lug'at — kalit → qiymat juftliklari to'plami:

talaba = {
    "ism": "Aziz",
    "yosh": 21,
    "kurslar": ["Python", "ML"],
}
 
talaba["ism"]                 # 'Aziz'
talaba["yosh"] = 22           # o'zgartirish
talaba["shahar"] = "Buxoro"   # yangi kalit qo'shish
del talaba["kurslar"]         # o'chirish
"ism" in talaba               # True — KALITLAR orasidan qidiradi
len(talaba)                   # 3

Yaratishning boshqa usullari:

dict(ism="Aziz", yosh=21)                 # kalitlar oddiy nom bo'lsa
dict(zip(["a", "b"], [1, 2]))             # {'a': 1, 'b': 2}
dict.fromkeys(["a", "b"], 0)              # {'a': 0, 'b': 0}
{x: x ** 2 for x in range(4)}             # {0: 0, 1: 1, 2: 4, 3: 9} — dict comprehension (7-bob)

Tartib#

Python 3.7'dan boshlab lug'at qo'shilish tartibini saqlaydi — bu til kafolati. {"b": 2, "a": 1} aylanilganda avval "b", keyin "a" keladi.

2. Ichki tuzilish: hash jadval#

Nega talaba["ism"] lug'atda 10 ta yoki 10 million element bo'lishidan qat'i nazar bir xil tez ishlaydi? Javob — hash jadval.

kalit: "ism"
hash("ism")
katta butun son, masalan 8541213…
% jadval_hajmi
→ katak raqami, masalan 5
jadval[5]
("ism", "Aziz") — to'g'ridan-to'g'ri o'qiladi
  1. Python kalitdan hash() funksiyasi orqali son hisoblaydi.
  2. Shu sondan jadvaldagi katak raqamini topadi.
  3. To'g'ridan-to'g'ri o'sha katakka boradi — qidirish shart emas.

Natijada qidirish, qo'shish va o'chirish o'rtacha O(1) — ro'yxatdagi in (O(n)) bilan solishtiring.

Hashlanish (hashability)#

Bundan muhim qoida kelib chiqadi: kalit hashlanadigan (hashable) bo'lishi kerak, ya'ni:

  • hash(kalit) hisoblanishi mumkin;
  • kalit hayoti davomida hash qiymati o'zgarmasligi kerak.

Shuning uchun immutable tiplar kalit bo'la oladi, mutable tiplar — yo'q:

Kalit bo'la oladiKalit bo'la olmaydi
int, float, str, bytes, bool, Nonelist
tuple (ichidagilar ham hashable bo'lsa)dict
frozensetset
koordinatalar = {(41.31, 69.24): "Toshkent", (39.65, 66.96): "Samarqand"}   # ✅ tuple kalit
kesh = {[1, 2]: "x"}       # ❌ TypeError: unhashable type: 'list'

Agar ro'yxat kalit bo'lishi mumkin bo'lganda va siz uni o'zgartirsangiz, uning hashi o'zgarar va lug'at uni "yo'qotib" qo'yardi. Python buni oldindan taqiqlaydi.

3. Xavfsiz o'qish: get, setdefault, pop#

Mavjud bo'lmagan kalitni o'qish — KeyError:

config = {"model": "claude-opus-5-5"}
config["temperature"]           # KeyError: 'temperature'

Xavfsiz usullar:

config.get("temperature")               # None
config.get("temperature", 1.0)          # 1.0 — standart qiymat
config.pop("model")                     # qiymatni olib, kalitni o'chiradi
config.pop("yo'q", None)                # yo'q bo'lsa — None, xato emas
config.setdefault("tags", []).append("test")   # yo'q bo'lsa yaratib, qiymatini qaytaradi

EAFP va LBYL#

Python'da ikki uslub bor:

# LBYL — "Look Before You Leap" (sakrashdan oldin qara)
if "temperature" in config:
    t = config["temperature"]
else:
    t = 1.0
 
# EAFP — "Easier to Ask Forgiveness than Permission" (ruxsat so'ragandan kechirim so'rash oson)
try:
    t = config["temperature"]
except KeyError:
    t = 1.0
 
# Ko'pincha eng yaxshisi — maxsus metod:
t = config.get("temperature", 1.0)

Python jamiyati EAFP uslubini ko'proq qo'llaydi (10-bobda batafsil), lekin lug'atlar uchun get ko'pincha eng toza yechim.

4. Aylanish va ko'rinishlar (views)#

narxlar = {"olma": 12000, "nok": 15000, "uzum": 22000}
 
narxlar.keys()       # dict_keys(['olma', 'nok', 'uzum'])
narxlar.values()     # dict_values([12000, 15000, 22000])
narxlar.items()      # dict_items([('olma', 12000), ...])
 
for meva, narx in narxlar.items():
    print(f"{meva:<6} {narx:>7,} so'm")

keys(), values(), items() — nusxa emas, jonli ko'rinish (view): lug'at o'zgarsa, ular ham o'zgaradi. keys() va items() to'plam amallarini ham qo'llaydi:

a = {"x": 1, "y": 2}
b = {"y": 3, "z": 4}
a.keys() & b.keys()     # {'y'} — umumiy kalitlar
a.keys() - b.keys()     # {'x'}

Saralash#

dict(sorted(narxlar.items()))                                 # kalit bo'yicha
dict(sorted(narxlar.items(), key=lambda kv: kv[1], reverse=True))   # qiymat bo'yicha, kamayish
max(narxlar, key=narxlar.get)                                 # 'uzum' — eng qimmatining kaliti

5. Birlashtirish va yangilash#

default = {"model": "claude-opus-5-5", "max_tokens": 1024, "effort": "medium"}
user = {"max_tokens": 4096}
 
# 1. Yangi lug'at — o'ngdagisi ustun
params = {**default, **user}          # Python 3.5+
params = default | user               # Python 3.9+ — eng o'qiladigan
 
# 2. Joyida yangilash
default.update(user)                  # default o'zgaradi
default |= user                       # xuddi shunday

Natija: {'model': 'claude-opus-5-5', 'max_tokens': 4096, 'effort': 'medium'}. Bu naqsh — "standart sozlamalar + foydalanuvchi sozlamalari" — har bir loyihada uchraydi.

6. To'plam (set)#

To'plam — takrorlanmaydigan, tartibsiz, hashlanadigan elementlar to'plami. Ichkarida — kalitlari bor, qiymatlari yo'q lug'at.

s = {1, 2, 3}
s.add(4)
s.discard(10)            # yo'q bo'lsa — jim (remove esa KeyError beradi)
bo_sh = set()            # {} — bu bo'sh LUG'AT, to'plam emas!
set([3, 1, 3, 2])        # {1, 2, 3} — dublikatlar yo'qoladi

Matematik amallar#

a = {1, 2, 3}
b = {2, 3, 4}
 
a | b      # {1, 2, 3, 4} — birlashma (union)
a & b      # {2, 3}       — kesishma (intersection)
a - b      # {1}          — ayirma (difference)
a ^ b      # {1, 4}       — simmetrik ayirma
{1, 2} <= a  # True       — qism to'plammi (subset)

Qachon to'plam ishlatish kerak#

1. Tez a'zolikni tekshirish. Bu eng muhim qo'llanish:

stop_words = {"va", "bilan", "uchun", "ham", "bu", "u"}   # set!
 
def filter_tokens(tokens: list[str]) -> list[str]:
    return [t for t in tokens if t not in stop_words]      # har tekshiruv O(1)

Agar stop_words ro'yxat bo'lsa va 500 so'zdan iborat bo'lsa, million tokenli matnda 500 million taqqoslash bo'ladi. To'plam bilan — million.

2. Dublikatlarni olib tashlash. set(lst) — lekin tartib yo'qoladi. Tartib kerak bo'lsa: list(dict.fromkeys(lst)).

3. Ikki to'plamni solishtirish. Masalan, train va test'da umumiy foydalanuvchilar bormi (ma'lumot sizib chiqishi — data leakage!):

train_users = set(train_df["user_id"])
test_users = set(test_df["user_id"])
umumiy = train_users & test_users
if umumiy:
    print(f"⚠️ {len(umumiy)} ta foydalanuvchi ikkala qismda ham bor!")

frozenset#

O'zgarmas to'plam — hashlanadi, shuning uchun lug'at kaliti yoki boshqa to'plam elementi bo'la oladi: {frozenset({"a", "b"}): 1}.

7. collections moduli — maxsus tuzilmalar#

Standart kutubxonadagi bu modul har kuni kerak bo'ladigan tayyor tuzilmalarni beradi.

Counter — sanash#

from collections import Counter
 
so_zlar = "the cat and the hat and the bat".split()
c = Counter(so_zlar)
c                         # Counter({'the': 3, 'and': 2, 'cat': 1, 'hat': 1, 'bat': 1})
c["the"]                  # 3
c["yo'q"]                 # 0 — KeyError emas!
c.most_common(2)          # [('the', 3), ('and', 2)]
c.total()                 # 8 (Python 3.10+)
c.update(["the", "dog"])  # qo'shimcha sanash
 
Counter("abracadabra").most_common(2)   # [('a', 5), ('b', 2)]

ML'da: sinflar balansini tekshirish — Counter(labels). Agar Counter({0: 9500, 1: 500}) chiqsa — ma'lumotlar nomutanosib (imbalanced), accuracy chalg'ituvchi metrika bo'ladi.

defaultdict — standart qiymatli lug'at#

from collections import defaultdict
 
# Guruhlash: har bir harf bilan boshlanadigan so'zlar
guruhlar = defaultdict(list)
for soz in ["olma", "anor", "nok", "orik", "nar"]:
    guruhlar[soz[0]].append(soz)     # kalit yo'q bo'lsa — avtomatik [] yaratiladi
 
dict(guruhlar)   # {'o': ['olma', 'orik'], 'a': ['anor'], 'n': ['nok', 'nar']}

defaultdict(int) — sanash uchun, defaultdict(list) — guruhlash uchun, defaultdict(set) — unikal guruhlash uchun.

deque — ikki tomonli navbat#

from collections import deque
 
q = deque([1, 2, 3])
q.append(4)          # o'ngga — O(1)
q.appendleft(0)      # chapga — O(1) (list.insert(0, x) — O(n))
q.popleft()          # chapdan olish — O(1) (list.pop(0) — O(n))
 
oxirgilar = deque(maxlen=3)   # faqat oxirgi 3 ta element saqlanadi
for i in range(5):
    oxirgilar.append(i)
print(oxirgilar)     # deque([2, 3, 4], maxlen=3)

deque(maxlen=N) — "oxirgi N ta" uchun ideal: chat'ning oxirgi N xabari, oxirgi 100 ta loss qiymatining o'rtachasi, reinforcement learning'dagi replay buffer.

namedtuple — nomlangan maydonli tuple#

from collections import namedtuple
 
Point = namedtuple("Point", ["x", "y"])
p = Point(3, 4)
p.x, p.y              # (3, 4) — nom bilan
p[0]                  # 3 — indeks bilan ham
x, y = p              # unpacking ham ishlaydi
p._replace(x=10)      # Point(x=10, y=4) — yangi obyekt
p._asdict()           # {'x': 3, 'y': 4}

Zamonaviy kodda ko'proq typing.NamedTuple yoki dataclass (13-bob) ishlatiladi — ular type hint'lar bilan yaxshiroq ishlaydi.

ChainMap — bir nechta lug'atni qatlam qilib ko'rish#

from collections import ChainMap
 
cli_args = {"lr": 0.1}
env = {"epochs": 20}
defaults = {"lr": 0.01, "epochs": 10, "batch_size": 32}
 
cfg = ChainMap(cli_args, env, defaults)   # chapdagisi ustun
cfg["lr"], cfg["epochs"], cfg["batch_size"]   # (0.1, 20, 32)

8. Qaysi tuzilmani tanlash kerak?#

VazifaTuzilmaNega
Tartiblangan elementlar, indeks bo'yicha kirishlistO(1) indeks
O'zgarmas yozuv, funksiyadan bir nechta qiymattupleMa'no + hashlanadi
Kalit bo'yicha qidirishdictO(1)
"Bormi?" tekshiruvi, dublikatlarni olib tashlashsetO(1) in
SanashCounterTayyor most_common
Guruhlashdefaultdict(list)Tekshiruvsiz append
Navbat, oxirgi N tadequeO(1) ikki tomonda
Raqamlar massivi, matematik amallarnumpy.ndarrayVektorlashtirish (19-bob)
Jadval ma'lumotlaripandas.DataFrameUstunlar, guruhlash, birlashtirish (20-bob)

9. Amaliyot: so'z chastotasi va oddiy "vocabulary"#

NLP'ning birinchi qadami — matndan lug'at (vocabulary) qurish: har bir so'zga raqam berish. Tokenizer'lar aynan shunday boshlanadi:

from collections import Counter
 
corpus = [
    "Python ML uchun eng mashhur til",
    "ML modellar ma'lumotdan o'rganadi",
    "Python va ML birga",
]
 
# 1. So'zlarni sanash
counts = Counter(word for line in corpus for word in line.lower().split())
 
# 2. Kamida 2 marta uchragan so'zlardan lug'at
SPECIAL = ["<pad>", "<unk>"]
vocab = SPECIAL + [w for w, n in counts.most_common() if n >= 2]
word2id = {w: i for i, w in enumerate(vocab)}
id2word = {i: w for w, i in word2id.items()}
 
 
def encode(text: str) -> list[int]:
    unk = word2id["<unk>"]
    return [word2id.get(w, unk) for w in text.lower().split()]
 
 
def decode(ids: list[int]) -> str:
    return " ".join(id2word[i] for i in ids)
 
 
print(word2id)                    # {'<pad>': 0, '<unk>': 1, 'ml': 2, 'python': 3}
print(encode("Python ML zo'r"))   # [3, 2, 1]
print(decode([3, 2, 1]))          # python ml <unk>

Bu yerda deyarli bobning hamma narsasi bor: Counter sanash uchun, most_common saralash uchun, dict comprehension ikki tomonlama lug'at uchun, get(w, unk) noma'lum so'zlar uchun. Haqiqiy tokenizer'lar (BPE, SentencePiece) murakkabroq, lekin g'oya aynan shu.

Nima noto'g'ri ketishi mumkin#

HolatNatijaTo'g'risi
d["yo'q_kalit"]KeyErrord.get(k, default)
{} bo'sh to'plam debBo'sh lug'atset()
Ro'yxatni kalit qilishTypeError: unhashable typetuple(lst)
dict.fromkeys(k, [])Hamma kalit bitta ro'yxatda{x: [] for x in k}
Aylanish paytida kalit qo'shish/o'chirishRuntimeErrorfor k in list(d):
defaultdictda if d[k]:Kalit yaratiladiif k in d:
Ichma-ich lug'atlarni | bilan birlashtirishIchki lug'at to'liq almashadiRekursiv merge
set(lst) tartibni saqlaydi debTartib yo'qoladilist(dict.fromkeys(lst))
Katta ro'yxatda inO(n) — sekinset
1, 1.0, True turli kalit debBitta kalitga birlashadiKalit tiplarini aralashtirmang
Amaliy topshiriq

1. Inverted index

Qidiruv tizimlarining asosi — inverted index. Hujjatlar ro'yxatidan {so'z: {hujjat_id, ...}} lug'atini quring, keyin search("python ml") funksiyasi ikkala so'z ham uchragan hujjatlar id'larini qaytarsin.

Maslahatni ko'rsatish

defaultdict(set): for doc_id, text in enumerate(docs): for w in text.lower().split(): index[w].add(doc_id). AND qidiruv — to'plamlar kesishmasi.

Amaliy topshiriq

2. Sinflar balansi

labels = ["spam"] * 120 + ["ham"] * 880 berilgan. Har bir sinf ulushini foizda chiqaring va "class weight"larni hisoblang: w_c = N / (K * n_c) (N — jami, K — sinflar soni, n_c — sinfdagi namunalar). Bu og'irliklar nomutanosib ma'lumotda model o'qitishda ishlatiladi.

Maslahatni ko'rsatish

Counter(labels), keyin har bir sinf uchun n / total. Og'irlik: total / (n_classes * n).

Amaliy topshiriq

3. Chuqur birlashtirish

deep_merge(a, b) funksiyasini yozing: ichma-ich lug'atlarni rekursiv birlashtirsin. deep_merge({"opt": {"lr": 1, "wd": 0}, "ep": 5}, {"opt": {"lr": 2}}) → {"opt": {"lr": 2, "wd": 0}, "ep": 5}.

Maslahatni ko'rsatish

Agar ikkala qiymat ham dict bo'lsa — rekursiv chaqiring, aks holda o'ngdagisini oling. Asl lug'atlarni o'zgartirmang.

Amaliy topshiriq

4. LRU kesh qo'lda

Oxirgi n ta ishlatilgan kalitni saqlaydigan kesh yozing: get(k) va put(k, v) metodlari bilan; joy tugaganda eng uzoq ishlatilmagan element o'chirilsin. Maslahat: oddiy dict tartibni saqlaydi — getda kalitni pop qilib qayta qo'shsangiz, u "eng yangi" bo'ladi; eng eskisi — next(iter(d)). (8-bobda tayyor functools.lru_cacheni ko'ramiz.)

Yodda saqlang
  • 01dict — hash jadval: qidirish, qo'shish, o'chirish o'rtacha O(1); 3.7+ da tartib saqlanadi.
  • 02Kalit hashlanadigan (immutable) bo'lishi kerak: str, int, tuple — ha; list, dict, set — yo'q.
  • 03get(k, default), setdefault, pop(k, None) — KeyError'siz ishlash.
  • 04default | user — sozlamalarni birlashtirish naqshi (sayoz!).
  • 05set — O(1) a'zolik tekshiruvi va to'plam amallari; {} — bo'sh lug'at, set() — bo'sh to'plam.
  • 06Counter — sanash, defaultdict — guruhlash, deque — navbat va oxirgi N ta, namedtuple — nomli yozuv.
  • 07Vazifaga mos tuzilma tanlash — performansning eng arzon usuli.

Mustahkamlash

Test va amaliy masalalar

Avval testni ishlang — har javobdan keyin izoh chiqadi. Keyin masalalarni shu yerning o'zida yechib, brauzerdagi haqiqiy Python bilan avtomatik tekshiring. Natijalaringiz kurs progressi sahifasida jamlanadi.

Test: topshirilmaganMasalalar: 0/3

Bilimni tekshirish

Bob bo'yicha test

12 ta savol · har javobdan keyin to'g'ri yoki xatoligi va izoh ko'rsatiladi · oxirida natija foizda.

Amaliy masalalar

Kodni yozing va «Tekshirish»ni bosing (yoki Ctrl/⌘ + Enter). Kodingiz shu brauzerda saqlanib turadi.

01So'z chastotasi

top_words(text, n) — matnni kichik harfga o'tkazib, bo'sh joylar bo'yicha bo'lib, eng ko'p uchragan n ta so'zni [(so'z, soni), ...] ko'rinishida qaytarsin (collections.Counter).

02Inverted index

build_index(docs) — {so'z: {hujjat_indekslari}} lug'atini qursin (kichik harf, split()). search(index, query) — so'rovdagi barcha so'zlar uchragan hujjatlar indekslarini saralangan ro'yxat qilib qaytarsin.

03Chuqur birlashtirish

deep_merge(a, b) — ichma-ich lug'atlarni rekursiv birlashtirsin (b ustun), asl lug'atlar o'zgarmasin. deep_merge({"opt": {"lr": 1, "wd": 0}, "ep": 5}, {"opt": {"lr": 2}}) → {"opt": {"lr": 2, "wd": 0}, "ep": 5}.