Topic notes

Sets

~8 min read7 runnable examples

These notes are written in Slovak. The examples run the same in any language.

You can run every example right here, then edit the code and see what changes. Your code runs only in this browser, in an isolated environment with no access to the internet or your account.

Množina (typ set) je skupina hodnôt bez opakovania a bez poradia – presne ako množina v matematike. Hodí sa vždy, keď nás zaujíma, či niečo v skupine je, a nie koľkokrát alebo na ktorom mieste: rôzne písmená v texte, unikátni návštevníci, spoločné prvky dvoch zoznamov. Zisťovanie, či je hodnota v množine, je navyše veľmi rýchle.

Čo sa naučíš

  • vytvoriť množinu a pridávať či odoberať prvky,
  • zistiť príslušnosť prvku operátorom in,
  • počítať zjednotenie, prienik a rozdiel množín,
  • použiť množinu na odstránenie duplikátov a porovnávanie skupín.

1Vytvorenie množiny

Množinu zapíšeme do zložených zátvoriek. Opakujúce sa hodnoty sa uložia iba raz:

>>> farby = {"červená", "modrá", "červená", "zelená"}
>>> len(farby)
3
>>> cisla = {3, 1, 3, 2, 1}
>>> cisla
{1, 2, 3}

Z iných postupností vytvorí množinu funkcia set. To je najjednoduchší spôsob, ako sa zbaviť duplikátov:

>>> set([1, 2, 2, 3, 3, 3])
{1, 2, 3}
>>> len(set("abrakadabra"))
5
>>> sorted(set("abrakadabra"))
['a', 'b', 'd', 'k', 'r']

1.1Množina nemá poradie

Prvky množiny nemajú pevné poradie ani indexy. Pri výpise sa môžu zobraziť v inom poradí, než v akom sme ich zapísali – a na inom počítači aj v inom poradí ako tu. Ak potrebuješ poradie, použi sorted(mnozina), ktorá vráti zoradený zoznam.

>>> m = {"jablko", "hruška", "slivka"}
>>> sorted(m)
['hruška', 'jablko', 'slivka']
>>> m[0]
TypeError: 'set' object is not subscriptable

1.2Čo môže byť v množine

Prvkami množiny môžu byť iba nemenné hodnoty: čísla, reťazce, n-tice. Zoznam do množiny vložiť nemožno:

>>> {(1, 2), (3, 4)}
{(1, 2), (3, 4)}
>>> {[1, 2]}
TypeError: unhashable type: 'list'

2Pridávanie a odoberanie

MetódaČo urobí
m.add(x)pridá prvok x (ak už tam je, nič sa nestane)
m.remove(x)odstráni x; ak tam nie je, chyba KeyError
m.discard(x)odstráni x, ak tam je; inak nič
m.clear()vyprázdni množinu
Python
navstevnici = set()
for meno in ["Ema", "Ján", "Ema", "Sofia", "Ján"]:
navstevnici.add(meno)
print(len(navstevnici), "rôzni návštevníci:", sorted(navstevnici))
navstevnici.discard("Tomáš") # nebol tam – nič sa nestane
navstevnici.remove("Ján")
print(sorted(navstevnici))

Výstup:

3 rôzni návštevníci: ['Ema', 'Ján', 'Sofia']
['Ema', 'Sofia']

3Príslušnosť: in

Operátor in (a not in) zistí, či prvok v množine je:

Python
samohlasky = {"a", "e", "i", "o", "u", "y"}
slovo = "programovanie"
for znak in slovo:
if znak in samohlasky:
print(znak, end="")
print()

Výstup:

oaoaie

Pri zozname musí Python pri in prechádzať prvky jeden po druhom. Množina si prvky ukladá tak, že odpoveď nájde takmer okamžite bez ohľadu na veľkosť. Ak sa v programe veľakrát pýtaš, či je niečo v skupine, ulož skupinu do množiny. O rýchlosti programov viac v téme Algoritmické úlohy.

4Množinové operácie

Množinové operácie poznáš z matematiky. V Pythone sa zapisujú operátormi (alebo metódami s rovnakým významom):

Vennov diagram dvoch množín A a B: časť len v A je A - B, prekrytie je A & B, časť len v B je B - A.
OperáciaOperátorMetódaVýsledok obsahuje prvky, ktoré sú…
zjednoteniea | ba.union(b)aspoň v jednej z množín
prienika & ba.intersection(b)v oboch množinách
rozdiela - ba.difference(b)v a, ale nie v b
symetrický rozdiela ^ ba.symmetric_difference(b)práve v jednej z nich
>>> a = {1, 2, 3, 4}
>>> b = {3, 4, 5, 6}
>>> a | b
{1, 2, 3, 4, 5, 6}
>>> a & b
{3, 4}
>>> a - b
{1, 2}
>>> b - a
{5, 6}
>>> a ^ b
{1, 2, 5, 6}

Porovnávať možno aj celé množiny: a <= b znamená „a je podmnožinou b“ (každý prvok a je aj v b).

>>> {1, 2} <= {1, 2, 3}
True
>>> {1, 4} <= {1, 2, 3}
False
>>> {3, 2, 1} == {1, 2, 3}
True

Dve množiny sa rovnajú, ak majú rovnaké prvky – na poradí zápisu nezáleží.

5Prechádzanie množiny

Cyklus for prejde všetky prvky, ale v nepredvídateľnom poradí. Ak na poradí záleží (napríklad pri výpise), prechádzaj sorted(m):

Python
znamky = {3, 1, 2}
for z in sorted(znamky):
print("známka", z)

Výstup:

známka 1
známka 2
známka 3

6Riešené úlohy

6.1Rôzne písmená v texte

Zadanie: Zisti, koľko rôznych písmen obsahuje veta, a vypíš ich abecedne. Zisti aj, ktoré písmená anglickej abecedy v nej chýbajú.

Riešenie: Množina písmen vznikne z textu po odstránení medzier a interpunkcie. Chýbajúce písmená sú rozdiel celej abecedy a písmen vety.

Python
veta = "Kde bolo, tam bolo, bolo raz jedno malé mestečko."
pismena = set()
for znak in veta.lower():
if znak.isalpha():
pismena.add(znak)
print(len(pismena), "rôznych písmen:", "".join(sorted(pismena)))
​
abeceda = set("abcdefghijklmnopqrstuvwxyz")
print("chýbajú:", "".join(sorted(abeceda - pismena)))

Výstup:

16 rôznych písmen: abdejklmnorstzéč
chýbajú: cfghipquvwxy

Veta, ktorá obsahuje všetky písmená abecedy, sa volá pangram – pre ňu by rozdiel vyšiel prázdny.

6.2Lotéria

Zadanie: Vyžrebuj 6 rôznych čísel od 1 do 49. Potom ich porovnaj so zadaným tipom a vypíš, koľko čísel tip uhádol.

Riešenie: Náhodné čísla pridávame do množiny, kým ich nie je 6 – opakované číslo sa do množiny nepridá, takže na konci máme istotu, že sú všetky rôzne. Počet uhádnutých čísel je veľkosť prieniku. (V ukážke je pevne nastavené random.seed.)

Python
import random
​
zrebovanie = set()
while len(zrebovanie) < 6:
zrebovanie.add(random.randint(1, 49))
tip = {3, 11, 17, 25, 31, 42}
print("Vyžrebované:", sorted(zrebovanie))
print("Tip:", sorted(tip))
print("Uhádnuté:", sorted(zrebovanie & tip), "–", len(zrebovanie & tip), "čísla")

Výstup:

Vyžrebované: [9, 16, 24, 35, 38, 39]
Tip: [3, 11, 17, 25, 31, 42]
Uhádnuté: [] – 0 čísla

Modul random má na to aj hotovú funkciu: random.sample(range(1, 50), 6) vráti 6 rôznych čísel.

6.3Spoločné záujmy

Zadanie: Dve osoby, A a B, vymenovali svoje záujmy. Vypíš spoločné záujmy, záujmy, ktoré má iba A, a všetky záujmy dohromady.

Python
a = {"futbal", "hudba", "programovanie", "šach"}
b = {"hudba", "kreslenie", "programovanie", "plávanie"}
print("spoločné:", sorted(a & b))
print("iba A:", sorted(a - b))
print("všetky:", sorted(a | b))

Výstup:

spoločné: ['hudba', 'programovanie']
iba A: ['futbal', 'šach']
všetky: ['futbal', 'hudba', 'kreslenie', 'plávanie', 'programovanie', 'šach']

6.4Ktoré hodnoty sa opakujú?

Zadanie: Vypíš hodnoty, ktoré sa v zozname vyskytujú viackrát.

Riešenie: Prejdeme zoznam a pamätáme si v množine hodnoty, ktoré sme už videli. Ak hodnotu už poznáme, je to opakovanie.

Python
z = [4, 7, 1, 7, 9, 4, 4, 2]
videne = set()
opakovane = set()
for x in z:
if x in videne:
opakovane.add(x)
else:
videne.add(x)
print(sorted(opakovane))

Výstup:

[4, 7]

7Časté chyby

  • {} nie je prázdna množina, ale prázdny slovník – použi set().
  • Indexovanie množiny (m[0]) nie je možné – množina nemá poradie; preveď ju na zoradený zoznam.
  • Spoliehanie sa na poradie pri výpise – výsledok môže vyzerať inak; na výpis použi sorted.
  • remove neexistujúceho prvku skončí chybou KeyError; použi discard alebo najprv in.
  • Zoznam v množine – prvky musia byť nemenné (čísla, reťazce, n-tice).

Zhrnutie

  • Množina {a, b, c} obsahuje každú hodnotu najviac raz a nemá poradie; prázdna je set().
  • set(postupnosť) odstráni duplikáty; len je počet rôznych hodnôt.
  • add, remove (chyba pri chýbajúcom prvku), discard (bez chyby).
  • x in m je veľmi rýchle – vhodné na časté zisťovanie príslušnosti.
  • a | b zjednotenie, a & b prienik, a - b rozdiel, a ^ b symetrický rozdiel, a <= b podmnožina.
  • Na výpis v poradí použi sorted(m).

Úlohy na precvičenie

  1. Načítaj vetu a vypíš počet rôznych slov (bez ohľadu na veľké a malé písmená).
  2. Zisti, či je zadaná veta pangram (obsahuje všetky písmená anglickej abecedy).
  3. Vygeneruj dve množiny po 10 náhodných čísel od 1 do 20 a vypíš ich prienik a zjednotenie.
  4. Z dvoch zoznamov mien vypíš mená, ktoré sú iba v jednom z nich.
  5. Načítaj čísla oddelené medzerou a zisti, či sú všetky rôzne (porovnaj dĺžku zoznamu a množiny).

Done reading?

Check what you remember with a few short tasks on the topic.