OzbekPython / Bob 08

Töplamlar (set)

Takrorlanmas elementlar töplami — yaratiş, qöşiş va öçiriş, birlaşma, kesişma, ayirma hamda takrorlarni olib taşlaş kabi amaliy vazifalar.

Boşlanğiç daraja18 daqiqa17 kod misoli8 / 24

Töplam nima?

Maktabdagi matematika darslarini eslang: töplam — bu takrorlanmaydigan elementlar majmuasi. Pythonʼdagi set ham aynan şu ğoyaga asoslangan. Töplamning ikki asosiy xususiyati bor:

  • Har bir element faqat bir marta uçraydi. Bir xil qiymatni ikki marta qöşsangiz, u baribir bitta bölib qoladi.
  • Tartib yöq. Töplamda indeks yöq, şuning uçun toplam[0] deb murojaat qilib bölmaydi.

Bu çeklovlar evaziga töplam ikki katta afzallik beradi: takrorlarni avtomatik olib taşlaydi va "bu element bormi?" degan savolga juda tez javob beradi.

Töplam yaratiş

Töplam jingalak qavslar {} bilan yoziladi yoki set() funksiyasi orqali boşqa ketma-ketlikdan yaratiladi.

Python
sonlar = {3, 1, 4, 1, 5, 9, 2, 6, 5}
print(sonlar)
print(len(sonlar))

harflar = set("kitobxon")
print(sorted(harflar))

royxatdan = set([10, 20, 10, 30, 20])
print(royxatdan)

Natija:

Natija
{1, 2, 3, 4, 5, 6, 9}
7
['b', 'i', 'k', 'n', 'o', 't', 'x']
{10, 20, 30}

Eʼtibor bering: 9 ta son yozdik, lekin töplamda 7 tasi qoldi — takrorlangan 1 va 5 tuşib qoldi.

Böş töplam tuzoği

Bu yerda köpçilik xato qiladi. {} — böş töplam emas, balki böş luğat! Çunki jingalak qavslar avval luğatlar uçun işlatilgan. Böş töplam faqat set() bilan yaratiladi.

Python
a = {}
b = set()

print(type(a))
print(type(b))
print(b)

Natija:

Natija
<class 'dict'>
<class 'set'>
set()

Töplamga nima qöyiş mumkin?

Töplam elementlari özgarmas (haşlanadigan) bölişi kerak: sonlar, satrlar, kortejlar. Röyxat yoki luğatni töplamga qöyib bölmaydi.

Python
nuqtalar = {(0, 0), (1, 2), (0, 0)}
print(len(nuqtalar))
print(sorted(nuqtalar))

try:
    yomon = {[1, 2], [3, 4]}
except TypeError as xato:
    print("Xato:", xato)

Natija:

Natija
2
[(0, 0), (1, 2)]
Xato: unhashable type: 'list'

Element qöşiş va öçiriş

MetodNima qiladi
add(x)bitta element qöşadi
update(...)bir neçta elementni (röyxat, kortej, boşqa töplamdan) qöşadi
remove(x)elementni öçiradi; yöq bölsa KeyError
discard(x)elementni öçiradi; yöq bölsa jim turadi
pop()ixtiyoriy bitta elementni olib, qaytaradi
clear()töplamni böşatadi
Python
teglar = {"python", "dastur"}

teglar.add("kitob")
teglar.add("python")          # allaqaçon bor - heç narsa özgarmaydi
print(sorted(teglar))

teglar.update(["sport", "musiqa"])
print(sorted(teglar))

teglar.remove("sport")
teglar.discard("kino")        # yöq, lekin xato ham yöq
print(sorted(teglar))

try:
    teglar.remove("kino")
except KeyError as xato:
    print("KeyError:", xato)

Natija:

Natija
['dastur', 'kitob', 'python']
['dastur', 'kitob', 'musiqa', 'python', 'sport']
['dastur', 'kitob', 'musiqa', 'python']
KeyError: 'kino'

remove() yoki discard() — qaysi biri? Agar elementning yöqligi dasturdagi xato belgisi bölsa, remove() muammoni darhol körsatadi. Agar "bölsa öçir, bölmasa mayli" degan maʼno bölsa, discard() qulayroq.

pop() haqida: töplamda tartib yöq, şuning uçun qaysi element olinişini oldindan aytib bölmaydi. U "qolgan işlardan istalgan bittasini ol" kabi holatlar uçun mos.

Python
vazifalar = {1, 2, 3}
while vazifalar:
    v = vazifalar.pop()
    print("Bajarildi:", v)
print("Qolgan:", vazifalar)

Natija:

Natija
Bajarildi: 1
Bajarildi: 2
Bajarildi: 3
Qolgan: set()

Töplamlar ustida amallar

Töplamlarning haqiqiy kuçi — matematikadagi kabi amallarda. Har bir amalni metod yoki operator bilan yoziş mumkin.

AmalMetodNatija
Birlaşmaa.union(b)ikkalasidagi hamma element
Kesişmaa.intersection(b)ikkalasida ham bor elementlar
Ayirmaa.difference(b)a da bor, b da yöq
Simmetrik ayirmaa.symmetric_difference(b)faqat bittasida bor elementlar

Ularga mos operatorlar: birlaşma — a | b, kesişma — a & b, ayirma — a - b, simmetrik ayirma — a ^ b.

Keling, ikki guruhdagi talabalar qaysi tögaraklarga qatnaşişini köraylik:

Python
futbol = {"Anvar", "Bobur", "Sardor", "Jasur"}
satranj = {"Bobur", "Laylo", "Jasur", "Madina"}

print("Birlaşma:", sorted(futbol | satranj))
print("Kesişma:", sorted(futbol & satranj))
print("Faqat futbol:", sorted(futbol - satranj))
print("Faqat satranj:", sorted(satranj - futbol))
print("Bittasiga:", sorted(futbol ^ satranj))

Natija:

Natija
Birlaşma: ['Anvar', 'Bobur', 'Jasur', 'Laylo', 'Madina', 'Sardor']
Kesişma: ['Bobur', 'Jasur']
Faqat futbol: ['Anvar', 'Sardor']
Faqat satranj: ['Laylo', 'Madina']
Bittasiga: ['Anvar', 'Laylo', 'Madina', 'Sardor']

Metodlar operatorlardan bitta farq qiladi: ular argument sifatida faqat töplamni emas, istalgan ketma-ketlikni (masalan, röyxatni) qabul qiladi. Operatorlarda esa ikki tomon ham töplam bölişi şart.

Python
a = {1, 2, 3}

print(a.union([3, 4, 5]))
print(a.intersection((2, 3, 9)))

try:
    print(a | [3, 4, 5])
except TypeError as xato:
    print("Xato:", xato)

Natija:

Natija
{1, 2, 3, 4, 5}
{2, 3}
Xato: unsupported operand type(s) for |: 'set' and 'list'

Qism töplam va kesişmaslik

Ikki töplam orasidagi munosabatni tekşiriş uçun uçta metod bor:

  • a.issubset(b) — a ning barça elementlari b da bormi? (operator: a <= b)
  • a.issuperset(b) — a da b ning barça elementlari bormi? (operator: a >= b)
  • a.isdisjoint(b) — ularda umumiy element umuman yöqmi?
Python
kerakli = {"pasport", "rasm", "attestat"}
topshirilgan = {"pasport", "rasm", "attestat", "maʼlumotnoma"}

print(kerakli.issubset(topshirilgan))
print(topshirilgan.issuperset(kerakli))
print(kerakli <= topshirilgan)

dam_kunlari = {"şanba", "yakşanba"}
ish_kunlari = {"duşanba", "seşanba", "juma"}
print(dam_kunlari.isdisjoint(ish_kunlari))

Natija:

Natija
True
True
True
True

Birinçi misol hayotiy vaziyat: hujjat qabul qilişda barça kerakli hujjatlar topşirilganini bitta qator bilan tekşiramiz.

frozenset — özgarmas töplam

frozenset — töplamning özgarmas varianti. Unga element qöşib yoki öçirib bölmaydi, lekin barça amallar (|, &, -, issubset va boşqalar) işlaydi. Özgarmas bölgani uçun uni luğat kaliti yoki boşqa töplamning elementi qiliş mumkin.

Python
asosiy_ranglar = frozenset({"qizil", "sariq", "kök"})
print("sariq" in asosiy_ranglar)

try:
    asosiy_ranglar.add("yaşil")
except AttributeError as xato:
    print("Xato:", xato)

# frozenset luğat kaliti sifatida
narxlar = {frozenset({"non", "sut"}): 15000}
print(narxlar[frozenset({"sut", "non"})])

Natija:

Natija
True
Xato: 'frozenset' object has no attribute 'add'
15000

Oxirgi qatorga qarang: kalitni {"sut", "non"} tartibida yozsak ham qiymat topildi, çunki töplamda tartib ahamiyatsiz.

Amaliy misollar

Takrorlarni olib taşlaş

Töplamning eng maşhur qöllanilişi. Foydalanuvçilar röyxatida takrorlangan elektron poçta manzillari bor deylik. set() ularni bir zumda tozalaydi. Agar asl tartibni saqlaş kerak bölsa, dict.fromkeys() usulidan foydalaning — luğat kalitlari ham takrorlanmaydi, lekin tartibni saqlaydi.

Python
pochta = ["ali@mail.uz", "vali@mail.uz", "ali@mail.uz", "gul@mail.uz", "vali@mail.uz"]

noyob = set(pochta)
print("Noyob manzillar soni:", len(noyob))

tartibli = list(dict.fromkeys(pochta))
print(tartibli)

Natija:

Natija
Noyob manzillar soni: 3
['ali@mail.uz', 'vali@mail.uz', 'gul@mail.uz']

Ikki sinf röyxatini soliştiriş

Ikki kun davomida darsga kelgan talabalar röyxati bor. Ikkala kun ham kelganlarni, faqat bir kun kelganlarni va umuman kelmaganlarni topamiz.

Python
guruh = {"Anvar", "Bobur", "Kamola", "Laylo", "Madina", "Sardor"}
dushanba = {"Anvar", "Kamola", "Laylo", "Sardor"}
seshanba = {"Anvar", "Bobur", "Laylo"}

print("Ikkala kun ham:", sorted(dushanba & seshanba))
print("Faqat bir kun:", sorted(dushanba ^ seshanba))
print("Heç kelmagan:", sorted(guruh - (dushanba | seshanba)))
print(f"Davomat (duşanba): {len(dushanba) / len(guruh):.0%}")

Natija:

Natija
Ikkala kun ham: ['Anvar', 'Laylo']
Faqat bir kun: ['Bobur', 'Kamola', 'Sardor']
Heç kelmagan: ['Madina']
Davomat (duşanba): 67%

Tez tekşiriş (in)

Röyxatda in har bir elementni birma-bir körib çiqadi: röyxat qança uzun bölsa, şunça sekin. Töplamda esa in element sonidan deyarli qatʼi nazar bir zumda işlaydi. Şuning uçun köp marta "bormi?" deb söraladigan maʼlumotni töplamda saqlaş maʼqul.

Python
taqiqlangan = {"spam", "reklama", "yutuq"}

xabarlar = [
    "Ertaga dars soat 9 da",
    "Katta yutuq sizni kutmoqda",
    "Kitobni olib keling",
]

for xabar in xabarlar:
    sozlar = set(xabar.lower().split())
    if sozlar & taqiqlangan:
        print("BLOK:", xabar)
    else:
        print("OK:  ", xabar)

Natija:

Natija
OK:   Ertaga dars soat 9 da
BLOK: Katta yutuq sizni kutmoqda
OK:   Kitobni olib keling

Bu yerda biz har bir xabarning sözlarini töplamga aylantirib, taqiqlangan sözlar bilan kesişmasini tekşirdik. Kesişma böş bölmasa (if uçun True), xabar bloklanadi.

Xulosa

  • Töplam (set) — takrorlanmaydigan, tartibsiz elementlar majmuasi; indeks yöq.
  • Böş töplam faqat set() bilan yaratiladi, {} esa böş luğat.
  • add(), update() qöşadi; remove() (xato beradi), discard() (xato bermaydi), pop(), clear() öçiradi.
  • Amallar: | birlaşma, & kesişma, - ayirma, ^ simmetrik ayirma.
  • issubset(), issuperset(), isdisjoint() töplamlar munosabatini tekşiradi.
  • frozenset — özgarmas töplam, luğat kaliti böla oladi.
  • Asosiy qöllanişlar: takrorlarni olib taşlaş, röyxatlarni soliştiriş, tez in tekşiruvi.

Maşqlar

  1. [5, 3, 5, 1, 3, 3, 8] röyxatidagi noyob sonlarni ösiş tartibida çiqaring va neçta son takrorlanib tuşib qolganini hisoblang.
Yeçim
Python
sonlar = [5, 3, 5, 1, 3, 3, 8]
noyob = set(sonlar)
print(sorted(noyob))
print(len(sonlar) - len(noyob))
  1. Ikki dökon assortimenti berilgan: {"non", "sut", "un", "qand"} va {"sut", "qand", "tuz", "guruç"}. Ikkala dökonda ham bor mahsulotlarni va faqat birinçi dökonda bor mahsulotlarni çiqaring.
Yeçim
Python
dokon1 = {"non", "sut", "un", "qand"}
dokon2 = {"sut", "qand", "tuz", "guruç"}
print(sorted(dokon1 & dokon2))
print(sorted(dokon1 - dokon2))
  1. Ikki söz bir xil harflardan tuzilganmi (takrorlarni hisobga olmasdan)? "kitob" va "tokib", "olma" va "anor" juftliklarini tekşiring.
Yeçim
Python
def bir_xil_harflar(a: str, b: str) -> bool:
    return set(a) == set(b)

print(bir_xil_harflar("kitob", "tokib"))
print(bir_xil_harflar("olma", "anor"))
  1. Kursni tugatiş uçun {"Python", "SQL", "Git"} fanlaridan ötiş kerak. Talaba {"Python", "Git", "HTML"} fanlaridan ötgan. U kursni tugata oladimi va qaysi fanlar qolgan?
Yeçim
Python
kerakli = {"Python", "SQL", "Git"}
otgan = {"Python", "Git", "HTML"}
print(kerakli.issubset(otgan))
print(sorted(kerakli - otgan))
  1. Matndagi noyob sözlar sonini toping (katta-kiçik harfni farqlamang): "Bugun havo iliq Ertaga ham havo iliq böladi".
Yeçim
Python
matn = "Bugun havo iliq Ertaga ham havo iliq böladi"
noyob = set(matn.lower().split())
print(len(noyob))
print(sorted(noyob))