aidoc.uz

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

Ro'yxatlar va tuple'lar

list va tuple qanday ishlaydi, metodlar va ularning tezligi, nusxalash (shallow va deep copy), saralash va key funksiyalari, unpacking va eng ko'p uchraydigan tuzoqlar.

Ro'yxat (list) — Python'da eng ko'p ishlatiladigan ma'lumot tuzilmasi. Dataset qatorlari, model bashoratlari, chat xabarlari tarixi, fayllar ro'yxati — hammasi ro'yxat. Tuple esa uning o'zgarmas "egizagi". Bu bobda ikkalasini ichki ishlashidan tortib professional ishlatilishigacha ko'ramiz.

▶ Video dars· Corey Schafer· 29:04· ingliz tilida
Python Tutorial for Beginners 4: Lists, Tuples, and Sets

Ro'yxatlar, tuple'lar va to'plamlar metodlari amaliy misollarda. Bobdagi nusxalash (shallow va deep copy) qismini alohida diqqat bilan o'qing.

YouTube'da ochish ↗

1. Ro'yxat — o'zgaruvchan ketma-ketlik#

bo_sh = []
sonlar = [3, 1, 4, 1, 5]
aralash = [1, "ikki", 3.0, None, [5, 6]]     # turli tiplar mumkin (lekin odatda yaxshi g'oya emas)
harflar = list("salom")                      # ['s', 'a', 'l', 'o', 'm']
juftlar = list(range(0, 10, 2))              # [0, 2, 4, 6, 8]

Indekslash va slicing satrlardagidek ishlaydi (3-bob) — farqi shundaki, ro'yxatni o'zgartirish mumkin:

lst = [10, 20, 30, 40, 50]
lst[0] = 99              # [99, 20, 30, 40, 50]
lst[1:3] = [0, 0, 0]     # [99, 0, 0, 0, 40, 50] — slice'ni boshqa uzunlikdagi ro'yxat bilan almashtirish
del lst[0]               # [0, 0, 0, 40, 50]
del lst[-2:]             # [0, 0, 0]

Ichki tuzilish: dinamik massiv#

Python ro'yxati — bu bog'langan ro'yxat (linked list) emas, dinamik massiv: xotirada ketma-ket joylashgan obyektlarga ko'rsatkichlar massivi.

list obyekti
uzunlik = 3, sig'im = 4
[ ptr | ptr | ptr | bo'sh ]
ketma-ket xotira — shuning uchun lst[i] juda tez
massiv
int 10 · str "salom" · list [1, 2]
obyektlar xotiraning turli joylarida
list obyektlarning o'zini emas, ularga havolalarni saqlaydi

Bundan ikkita muhim xulosa:

  1. lst[i] — O(1), ya'ni ro'yxat qanchalik katta bo'lmasin, bir zumda.
  2. Ro'yxat oxiriga qo'shish odatda tez, chunki Python oldindan ortiqcha joy (sig'im) ajratib qo'yadi. Joy tugasa — kattaroq massiv ajratiladi va hamma ko'rsatkichlar ko'chiriladi (lekin bu kamdan-kam bo'ladi, shuning uchun o'rtacha O(1)).

Metodlar va ularning narxi#

AmalMisolMurakkablikIzoh
Oxiriga qo'shishlst.append(x)O(1)Eng ko'p ishlatiladigan
Ko'p element qo'shishlst.extend(boshqa)O(k)lst += boshqa bilan bir xil
Oxiridan olishlst.pop()O(1)
Boshidan olishlst.pop(0)O(n)Hamma elementlar siljiydi!
O'rtaga qo'shishlst.insert(i, x)O(n)
Qiymat bo'yicha o'chirishlst.remove(x)O(n)Birinchi uchraganini; yo'q bo'lsa ValueError
Qidirishx in lst, lst.index(x)O(n)Har birini tekshiradi
Sanashlst.count(x)O(n)
Saralashlst.sort()O(n log n)Joyida
Teskarilst.reverse()O(n)Joyida
Uzunliklen(lst)O(1)Saqlab qo'yilgan
lst = [3, 1, 2]
lst.append(4)          # [3, 1, 2, 4]
lst.extend([5, 6])     # [3, 1, 2, 4, 5, 6]
lst.insert(0, 0)       # [0, 3, 1, 2, 4, 5, 6]
oxirgi = lst.pop()     # 6, lst = [0, 3, 1, 2, 4, 5]
lst.remove(3)          # [0, 1, 2, 4, 5]

append va extend farqi:

a = [1, 2]
a.append([3, 4])       # [1, 2, [3, 4]] — ro'yxat BITTA element sifatida
b = [1, 2]
b.extend([3, 4])       # [1, 2, 3, 4]

Ro'yxat operatorlari#

[1, 2] + [3]           # [1, 2, 3] — yangi ro'yxat
[0] * 4                # [0, 0, 0, 0]
2 in [1, 2, 3]         # True
len([1, 2, 3])         # 3
min(lst), max(lst), sum(lst)

2. Nusxalash: eng muhim mavzu#

2-bobda b = a nusxa emasligini ko'rdik. Endi nusxalashning ikki turini farqlaymiz.

Sayoz nusxa (shallow copy)#

a = [1, 2, 3]
b = a.copy()       # yoki list(a), yoki a[:]
b.append(4)
print(a)           # [1, 2, 3] — a daxlsiz

Lekin ro'yxat ichida mutable obyektlar bo'lsa:

a = [[1, 2], [3, 4]]
b = a.copy()
b[0].append(99)    # ichki ro'yxatni o'zgartirish
b.append([5])      # tashqi ro'yxatga qo'shish
print(a)           # [[1, 2, 99], [3, 4]]       ← ichki o'zgarish ko'rindi!
print(b)           # [[1, 2, 99], [3, 4], [5]]

Sayoz nusxa faqat tashqi ro'yxatni nusxalaydi — ichidagi havolalar o'sha-o'sha obyektlarga ishora qiladi.

a → [ • , • ]
[1, 2, 99] [3, 4]
umumiy ichki obyektlar
b → [ • , • , • ]
Sayoz nusxa: ikki xil tashqi ro'yxat, lekin ichki ro'yxatlar umumiy

Chuqur nusxa (deep copy)#

import copy
 
a = [[1, 2], [3, 4]]
c = copy.deepcopy(a)    # hamma darajani rekursiv nusxalaydi
c[0].append(7)
print(a)                # [[1, 2], [3, 4]] — to'liq daxlsiz
UsulTashqi ro'yxatIchki obyektlarQachon
b = aUmumiyUmumiyHech qachon "nusxa" uchun
a.copy(), a[:], list(a)YangiUmumiyIchida immutable (son, satr) bo'lsa
copy.deepcopy(a)YangiYangiIchma-ich mutable tuzilmalar (konfiguratsiya, JSON)

2D ro'yxat tuzog'i#

grid = [[0] * 3] * 3        # 3x3 matritsa... shundaymi?
grid[0][0] = 1
print(grid)                 # [[1, 0, 0], [1, 0, 0], [1, 0, 0]]  ← uchala qator o'zgardi!

* 3 ichki ro'yxatni 3 marta nusxalamaydi — bitta ro'yxatga 3 ta havola yaratadi. To'g'ri usul:

grid = [[0] * 3 for _ in range(3)]    # har qator — yangi ro'yxat
grid[0][0] = 1
print(grid)                           # [[1, 0, 0], [0, 0, 0], [0, 0, 0]]

(Amalda matritsalar uchun NumPy ishlatiladi: np.zeros((3, 3)) — 19-bob.)

3. Saralash#

Ikki usul:

lst = [3, 1, 2]
yangi = sorted(lst)    # yangi ro'yxat qaytaradi, lst o'zgarmaydi; HAR QANDAY iterable'ni qabul qiladi
lst.sort()             # joyida saralaydi, None qaytaradi; faqat list uchun

key — saralash mezoni#

key — har bir elementdan "saralash qiymatini" oladigan funksiya:

so_zlar = ["banana", "Olma", "nok", "anor"]
 
sorted(so_zlar)                          # ['Olma', 'anor', 'banana', 'nok'] — katta harf oldin!
sorted(so_zlar, key=str.lower)           # ['anor', 'banana', 'nok', 'Olma']
sorted(so_zlar, key=len)                 # ['nok', 'Olma', 'anor', 'banana']
sorted(so_zlar, key=len, reverse=True)   # eng uzunidan

Bir nechta mezon bo'yicha#

key tuple qaytarsa — avval birinchi element, teng bo'lsa ikkinchisi bo'yicha saralanadi:

talabalar = [("Ali", 85), ("Vali", 92), ("Gani", 85), ("Soli", 70)]
 
# ball bo'yicha kamayish, teng bo'lsa ism bo'yicha o'sish
sorted(talabalar, key=lambda t: (-t[1], t[0]))
# [('Vali', 92), ('Ali', 85), ('Gani', 85), ('Soli', 70)]

lambda — kichik nomsiz funksiya (8-bob). operator.itemgetter tezroq va ba'zan o'qilishi osonroq:

from operator import itemgetter
 
sorted(talabalar, key=itemgetter(1), reverse=True)
max(talabalar, key=itemgetter(1))      # ('Vali', 92) — min/max ham key qabul qiladi

Barqarorlik (stability). Python'ning saralash algoritmi (Timsort) barqaror: teng elementlar asl tartibini saqlaydi. Shuning uchun murakkab saralashni bosqichma-bosqich qilish mumkin — avval ikkinchi darajali mezon, keyin asosiy mezon bo'yicha.

Saralangan ro'yxatda tez qidirish: bisect#

import bisect
 
chegaralar = [60, 75, 90]          # baho chegaralari
baholar = ["F", "C", "B", "A"]
 
def baho(ball: int) -> str:
    return baholar[bisect.bisect_right(chegaralar, ball)]
 
print([baho(b) for b in [45, 60, 74, 89, 95]])   # ['F', 'C', 'C', 'B', 'A']

bisect ikkilik qidiruv (binary search) — O(log n). Saralangan ro'yxatga tartibni buzmasdan qo'shish: bisect.insort(lst, x).

4. Tuple — o'zgarmas ketma-ketlik#

nuqta = (3, 4)
rgb = 255, 128, 0          # qavssiz ham tuple
bitta = (5,)               # BITTA elementli tuple — vergul shart!
emas = (5)                 # bu shunchaki int 5
bo_sh = ()

(5) — tuple emas, qavs ichidagi son. Tuple'ni vergul yaratadi, qavs emas.

Nega tuple kerak, list bor-ku?#

listtuple
O'zgaruvchanlikMutableImmutable
Ma'nosiBir xil turdagi elementlar to'plami (ro'yxat)Turli ma'noli maydonlardan iborat yozuv
Misol[85, 92, 78] — ballar("Ali", 25, "Toshkent") — bitta odam
Lug'at kaliti bo'la oladimiYo'qHa (ichidagilar ham immutable bo'lsa)
Xotira / tezlikBiroz ko'proqBiroz kamroq

Asosiy farq — ma'no. Tuple — "bu narsalar birga bitta yozuvni tashkil qiladi va o'zgarmaydi" degan signal. Funksiyadan bir nechta qiymat qaytarish, koordinatalar, lug'at kalitlari, tensor shakllari (shape = (32, 3, 224, 224)) — hammasi tuple.

def statistika(sonlar: list[float]) -> tuple[float, float, float]:
    return min(sonlar), max(sonlar), sum(sonlar) / len(sonlar)
 
kichik, katta, ortacha = statistika([4, 8, 15, 16, 23, 42])

"O'zgarmas" — lekin nisbatan#

t = ([1, 2], 3)
t[0].append(3)       # ruxsat! Tuple o'zgarmadi — u hamon o'sha ro'yxatga ishora qiladi
print(t)             # ([1, 2, 3], 3)
t[0] = [9]           # TypeError — havolani almashtirib bo'lmaydi

Tuple faqat o'zining havolalarini o'zgarmas qiladi. Ichida ro'yxat bo'lsa — u tuple hash qilinmaydi va lug'at kaliti bo'la olmaydi.

5. Unpacking — ochib tayinlash#

x, y = (3, 4)
ism, yosh, shahar = ["Ali", 25, "Toshkent"]
 
birinchi, *qolgan = [1, 2, 3, 4]        # 1, [2, 3, 4]
*boshi, oxirgi = [1, 2, 3, 4]           # [1, 2, 3], 4
bosh, *orta, oxir = range(6)            # 0, [1, 2, 3, 4], 5
 
x, (y, z) = 1, (2, 3)                   # ichma-ich
 
for ism, ball in [("Ali", 85), ("Vali", 92)]:   # siklda ochish
    ...
 
_, ikkinchi, _ = (1, 2, 3)              # kerakmas qiymatlar uchun _

Elementlar soni mos kelmasa — ValueError: too many values to unpack.

* bilan ochish (spread)#

a = [1, 2]
b = [3, 4]
birlashgan = [*a, *b, 5]           # [1, 2, 3, 4, 5]
print(*a)                          # print(1, 2) — argument sifatida ochish

Matritsani transpoze qilish — zip(*...)#

m = [[1, 2, 3],
     [4, 5, 6]]
t = [list(qator) for qator in zip(*m)]
# [[1, 4], [2, 5], [3, 6]]

zip(*m) — zip([1, 2, 3], [4, 5, 6]) bilan bir xil. Bu hiyla juftliklar ro'yxatini ikki ro'yxatga ajratishda ham ishlatiladi:

juftlar = [("Ali", 85), ("Vali", 92), ("Gani", 78)]
ismlar, ballar = zip(*juftlar)
# ismlar = ('Ali', 'Vali', 'Gani'), ballar = (85, 92, 78)

6. Ro'yxat bilan ishlashning foydali usullari#

lst = [5, 3, 8, 1]
 
any(x > 7 for x in lst)       # True — kamida bittasi
all(x > 0 for x in lst)       # True — hammasi
sum(x for x in lst if x > 2)  # 16
max(lst, default=None)        # bo'sh ro'yxat uchun xato o'rniga default
 
list(reversed(lst))           # [1, 8, 3, 5]
lst[::-1]                     # [1, 8, 3, 5]
 
# Dublikatlarni tartibni saqlab olib tashlash
unikal = list(dict.fromkeys([3, 1, 3, 2, 1]))   # [3, 1, 2]
 
# Ro'yxatni teng bo'laklarga (batch) bo'lish
def batched(items: list, size: int) -> list[list]:
    return [items[i:i + size] for i in range(0, len(items), size)]
 
batched(list(range(7)), 3)    # [[0, 1, 2], [3, 4, 5], [6]]

Python 3.12'dan boshlab standart kutubxonada itertools.batched bor (7-bobda ko'ramiz) — u tuple'lar qaytaradi va har qanday iterable bilan ishlaydi.

7. Amaliyot: chat tarixi#

LLM bilan suhbat — xabarlar ro'yxati. Ko'p qo'llaniladigan amallar:

Message = dict[str, str]
 
history: list[Message] = [
    {"role": "user", "content": "Salom!"},
    {"role": "assistant", "content": "Salom! Qanday yordam bera olaman?"},
    {"role": "user", "content": "Python nima?"},
    {"role": "assistant", "content": "Python — dasturlash tili..."},
]
 
 
def add_turn(history: list[Message], user: str, assistant: str) -> list[Message]:
    """Yangi ro'yxat qaytaradi — asl tarix o'zgarmaydi."""
    return [*history, {"role": "user", "content": user}, {"role": "assistant", "content": assistant}]
 
 
def last_turns(history: list[Message], n: int) -> list[Message]:
    """Oxirgi n ta savol-javob juftligi (kontekst oynasini tejash uchun)."""
    return history[-2 * n:] if n > 0 else []
 
 
def total_chars(history: list[Message]) -> int:
    return sum(len(m["content"]) for m in history)
 
 
print(len(last_turns(history, 1)), total_chars(history))

E'tibor bering: add_turn asl ro'yxatni o'zgartirmaydi — yangisini qaytaradi. Bu xatolarni kamaytiradi: masalan, bir xil "boshlang'ich tarix"dan bir nechta turli suhbat davom ettirsangiz, ular bir-biriga aralashmaydi.

Nima noto'g'ri ketishi mumkin#

HolatNatijaTo'g'risi
b = a nusxa deb o'ylashIkki nom bitta ro'yxatdaa.copy()
Ichma-ich tuzilmani .copy()Ichki o'zgarishlar asl nusxaga o'tadicopy.deepcopy()
[[0] * n] * mHamma qator bitta obyekt[[0] * n for _ in range(m)]
lst = lst.sort()Nonelst.sort() yoki sorted()
lst.append([1, 2]) "qo'shish" debIchma-ich ro'yxatextend
(5) tuple debint(5,)
Navbat uchun pop(0)O(n) — sekincollections.deque
Katta ro'yxatda in sikldaO(n²)set
max([])ValueErrormax(lst, default=...)
Katta-kichik harfli satrlarni saralashKatta harflar oldinkey=str.lower
Amaliy topshiriq

1. Nusxa topishmoqlari

Kodni bajarmasdan natijani yozing, keyin tekshiring:

import copy
a = [[1], [2]]
b = a
c = a[:]
d = copy.deepcopy(a)
a[0].append(10)
a.append([3])
print(b, c, d, sep="\n")
Maslahatni ko'rsatish

Har bir qatorda: yangi tashqi obyekt yaratildimi? Ichki obyektlar umummi? id() bilan tekshiring.

Amaliy topshiriq

2. Top-k bashoratlar

Model 5 sinf uchun ehtimollar qaytardi: probs = [0.05, 0.6, 0.1, 0.2, 0.05], classes = ["mushuk", "it", "ot", "sigir", "qo'y"]. Eng yuqori ehtimolli 3 ta sinfni [("it", 0.6), ("sigir", 0.2), ("ot", 0.1)] ko'rinishida qaytaruvchi top_k(probs, classes, k) funksiyasini yozing.

Maslahatni ko'rsatish

sorted(zip(ehtimollar, sinflar), reverse=True)[:k] yoki sorted(range(len(p)), key=p.__getitem__, reverse=True)[:k].

Amaliy topshiriq

3. Train/test bo'lish

train_test_split(data, test_ratio=0.2, seed=42) funksiyasini yozing: asl ro'yxatni o'zgartirmasin, aralashtirsin (random moduli, seed bilan — natija har safar bir xil bo'lsin), ikki ro'yxat qaytarsin. Hech bir element ikkala qismga tushmasligini assert bilan tekshiring.

Maslahatni ko'rsatish

random.Random(seed).shuffle(nusxa) — asl ro'yxatni o'zgartirmaslik uchun avval nusxa oling. Bo'lish nuqtasi: int(len * (1 - test_ratio)).

Amaliy topshiriq

4. Sliding window

windows(seq, size) funksiyasini yozing: ketma-ketlikdan "sirpanuvchi oyna"lar ro'yxatini qaytarsin: windows([1, 2, 3, 4, 5], 3) → [[1, 2, 3], [2, 3, 4], [3, 4, 5]]. Bu vaqt qatorlari (time series) va matnni bo'laklashda (chunking) ishlatiladi. Bonus: step parametrini qo'shing — windows(seq, 3, step=2) → [[1, 2, 3], [3, 4, 5]].

Yodda saqlang
  • 01list — havolalarning dinamik massivi: indeks va append O(1), insert/pop(0)/in — O(n).
  • 02b = a — nusxa emas; a.copy() — sayoz nusxa; copy.deepcopy() — to'liq nusxa.
  • 03[[0]*n]*m — bitta qatorga m ta havola; list comprehension ishlating.
  • 04sorted() yangi ro'yxat, .sort() joyida va None qaytaradi; key= va tuple kalitlar bilan istalgan tartib.
  • 05Tuple — o'zgarmas yozuv; bitta elementli tuple uchun vergul shart: (5,).
  • 06Unpacking: a, *b = ...; zip(*m) — transpoze va juftlarni ajratish.
  • 07Funksiyalar imkon qadar yangi ro'yxat qaytarsin — asl ma'lumotni o'zgartirmasin.

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.

01Top-k bashoratlar

top_k(probs, classes, k) — eng yuqori ehtimolli k ta sinfni [(sinf, ehtimol), ...] ko'rinishida, ehtimol kamayishi tartibida qaytarsin.

02Train/test bo'linishi

train_test_split(data, test_ratio=0.2, seed=42) → (train, test): asl ro'yxat o'zgarmasin, random.Random(seed) bilan aralashtirilsin, test hajmi int(len(data) * test_ratio).

03Sirpanuvchi oyna

windows(seq, size, step=1) — windows([1,2,3,4,5], 3) → [[1,2,3],[2,3,4],[3,4,5]]; windows([1,2,3,4,5], 3, step=2) → [[1,2,3],[3,4,5]]. To'liq bo'lmagan oynalar qo'shilmasin.