summaryrefslogtreecommitdiff
path: root/python/problems/dictionaries/dict_sl.html
diff options
context:
space:
mode:
Diffstat (limited to 'python/problems/dictionaries/dict_sl.html')
-rw-r--r--python/problems/dictionaries/dict_sl.html598
1 files changed, 598 insertions, 0 deletions
diff --git a/python/problems/dictionaries/dict_sl.html b/python/problems/dictionaries/dict_sl.html
new file mode 100644
index 0000000..8b7966d
--- /dev/null
+++ b/python/problems/dictionaries/dict_sl.html
@@ -0,0 +1,598 @@
+<!DOCTYPE html>
+<html lang="sl">
+<head>
+<meta charset="utf-8" />
+<title></title>
+<link rel="stylesheet" type="text/css" href="/css/codeq.css" />
+<link rel="stylesheet" type="text/css" href="../../style.css" />
+</head>
+<body>
+
+<h2>Slovar</h2>
+
+<p>Poglejmo še enkrat sezname. Seznam je nekakšna zbirka nekih poljubnih
+ reči, pri čemer je vsaka reč v svojem "predalčku", predalčki pa so
+ oštevilčeni. Prvi ima številko 0, drugi 1, tretji 2 in tako naprej. Za
+ vsak predalček lahko pogledamo, kaj je v njem, spremenimo njegovo vsebino,
+ predalčke lahko odvzemamo in dodajamo.
+
+<pre>>>> s = [6, 9, 4, 1]
+>>> s[1]
+9
+>>> s.append(7)
+>>> s
+[6, 9, 4, 1, 7]
+>>> del s[3]
+>>> s
+[6, 9, 4, 7]
+>>> s[-2:]
+[4, 7]</pre>
+
+<p>Slovar (angl. <em>dictionary</em>, podatkovni tip pa se imenuje
+ <code>dict</code>) je podoben seznamu, le da se na predalčke sklicujemo z
+ njihovimi <em>ključi</em> (angl. <em>key</em>, ki so lahko števila, lahko
+ pa tudi nizi, logične vrednosti, terke... Temu, kar je shranjeno v predalčku
+ bomo rekli <em>vrednost</em> (<em>value</em>). </p>
+
+<p>Seznam in slovar se že od daleč (če niste kratkovidni) razlikujeta po
+ oglatosti. Seznam smo opisali tako, da smo v <em>oglatih oklepajih</em>
+ našteli njihove <em>elemente</em>. Slovar opišemo tako, da v <em>zavitih
+ oklepajih</em> naštejemo pare <em>ključ: vrednost</em>.
+
+<p>Stalno omenjani Benjamin si lahko takole sestavi slovar s telefonskimi
+ številkami svojih oboževalk:
+<pre>stevilke = {"Ana": "041 310239", "Berta": "040 318319", "Cilka": "041 103194", "Dani": "040 193831",
+ "Eva": "051 123123", "Fanči": "040 135367", "Helga": "+49 175 4728 475"}</pre>
+
+<p>Do vrednosti, shranjenih v slovarju, pride podobno kot do vrednosti v
+ seznamu: z indeksiranjem, le da v oglate oklepaje ne napiše zaporedne
+ številke, temveč ključ.</p>
+
+<pre>>>> stevilke["Ana"]
+'041 310239'
+>>> stevilke["Dani"]
+'040 193831'</pre>
+
+<p>Slovarji ne poznajo vrstnega reda. V slovarju ni prvega, drugega, tretjega
+ elementa. Ne le zato, ker oznake niso številke. Ne, slovar si v resnici ne
+ zapomni vrstnega reda, v katerem smo našteli elemente, niti ne vrstnega
+ reda, v katerem jih dodajamo.</p>
+
+<pre>>>> stevilke
+{'Dani': '040 193831', 'Fanči': '040 135367', 'Helga': '+49 175 4728 475',
+'Eva': '051 123123', 'Cilka': '041 103194', 'Berta': '040 318319',
+'Ana': '041 310239'}</pre>
+
+<p>(Čemu?! Čemu je to potrebno? Čemu zmeša vrstni red?! Mar ne more zlagati
+ teh reči lepo po vrsti? Izvedeli boste drugo leto. V resnici ni zmešan,
+ temveč prav premeteno premetan. V tem, drugače preurejenem seznamu lahko išče
+ veliko hitreje.)</p>
+
+<p>Ker ni vrstnega reda, tudi ni rezin.</p>
+
+<pre>>>> stevilke["Ana":"Cilka"]
+Traceback (most recent call last):
+ File "<interactive input>", line 1, in <module>
+TypeError: unhashable type</pre>
+
+<p>Tole sporočilo o napaki je sicer zelo čudno, vendar povsem smiselno. Boste
+razumeli, ko boste veliki. ;)</p>
+
+<p>O "mehaniki" slovarjev morate vedeti le tole: slovarji so hitri, saj
+ elementov v resnici ne iščejo. Na nek za zdaj skrivnosten način "vedo", kje
+ je vrednost, ki pripada danemu ključu. Ne da bi iskali, vedo, kam morajo
+ pogledati. Tudi dodajanje novih elementov v slovar je zelo hitro, enako tudi
+ brisanje. Cena, ki jo plačamo za to, je dvojna. Ključi so lahko le
+ podatkovni tipi, ki so nespremenljivi. Nespremenljivi podatkovni tipi so,
+ vemo, nizi, števila, logične vrednosti in terke. Zgoraj smo kot ključ
+ uporabili niz. To je OK. Če bi poskušali kot ključ uporabiti seznam, ne bi
+ šlo. (V resnici je stvar malenkost bolj zapletena, ključ je lahko vsak
+ podatkovni tip, ki je "razpršljiv", vendar to ni za bruce). Omejitve
+ veljajo le za ključe. Vrednost je lahko karkoli.</p>
+
+<p>Drugi obrok cene, ki jo plačamo za učinkovitost slovarjev, je poraba
+ pomnilnika: slovar porabi nekako dvakrat več pomnilnika kot seznam. Koliko,
+ točno, več, je odvisno od velikost slovarja in tega, kaj shranjujemo.
+ Pri tem predmetu se s pomnilnikom ne obremenjujte.</p>
+
+<p>Aha, še tretji obrok cene, iz drobnega tiska: vsak ključ se lahko pojavi
+ največ enkrat. Če poskušamo prirediti neko vrednost ključu, ki že obstaja, le
+ povozimo staro vrednost. Ampak to je tako ali tako pričakovati. Tudi v
+ seznamu nimamo nikoli dveh različnih elementov na istem mestu.</p>
+
+<h4>Kaj lahko počnemo s slovarji?</h4>
+
+<p>Lahko jim dodajamo nove elemente: preprosto priredimo jim nov element.</p>
+
+<pre>>>> stevilke["Iva"] = "040 222333"
+>>> stevilke
+{'Dani': '040 193831', 'Fanči': '040 135367', 'Iva': '040 222333',
+'Helga': '+49 175 4728 475', 'Eva': '051 123123', 'Cilka': '041 103194',
+'Berta': '040 318319', 'Ana': '041 310239'}</pre>
+
+<p><code>append</code> ne obstaja, saj nima smisla: ker ni vrstnega reda, ne
+moremo dodajati na konec. Prav tako (ali pa še bolj) ne obstaja
+<code>insert</code>, saj prav tako (ali pa še bolj) nima smisla.
+
+<p>Vprašamo se lahko, ali v seznamu obstaja določen ključ.</p>
+
+<pre>>>> "Cilka" in stevilke
+True
+>>> "Jana" in stevilke
+False</pre>
+
+<p>Če se Cilka skrega z Benjaminom, jo lahko le-ta pobriše (mislim, pobriše
+ njeno številko).</p>
+
+<pre>>>> del stevilke["Cilka"]
+>>> stevilke
+{'Dani': '040 193831', 'Fanči': '040 135367', 'Iva': '040 222333',
+'Helga': '+49 175 4728 475', 'Eva': '051 123123',
+'Berta': '040 318319', 'Ana': '041 310239'}
+>>> "Cilka" in stevilke
+False</pre>
+
+<p>Če gremo prek slovarjev z zanko <code>for</code>, dobimo vrednosti
+ ključev.</p>
+
+<pre>>>> for ime in stevilke:
+... print(ime)
+...
+Dani
+Fanči
+Iva
+Helga
+Eva
+Berta
+Ana</pre></p>
+
+Seveda lahko ob vsakem imenu izpišemo tudi številko.
+
+<pre>>>> for ime in stevilke:
+... print(ime + ":", stevilke[ime])
+...
+Dani: 040 193831
+Fanči: 040 135367
+Iva: 040 222333
+Helga: +49 175 4728 475
+Eva: 051 123123
+Cilka: 041 103194
+Berta: 040 318319
+Ana: 041 310239</pre>
+
+<p>Vendar to ni najbolj praktično. Pomagamo si lahko s tremi metodami slovarja,
+ ki vrnejo vse ključe, vse vrednosti in vse pare ključ-vrednost. Imenujejo
+ se (ne preveč presenetljivo) <code>keys()</code>, <code>values()</code> in
+ <code>items()</code>. Delamo se lahko, da vračajo sezname ključev,
+ vrednosti oziroma parov ... čeprav v resnici vračajo le nekaj, prek česar
+ lahko gremo z zanko <code>for</code>.
+
+<p>Najprej poglejmo <code>items()</code>.</p>
+
+<pre>>>> for t in stevilke.items():
+... ime, stevilka = t
+... print(ime + ":", stevilka)</pre>
+
+<p>Tole zgoraj je bilo seveda grdo. Lepo se reče takole:</p>
+
+<pre>>>> for ime, stevilka in stevilke.items():
+... print(ime + ":", stevilke)</pre>
+
+<p>Tako kot sem ob zanki for težil, da ne uporabljajte
+<code>for i in range(len(s))</code> temveč <code>for e in s</code> in da
+že v glavi zanke razpakirajte terko, kadar je to potrebno, bom težil tudi
+tule: uporabljajte <code>items</code> in vaši programi bodo preglednejši in
+s tem pravilnejši.</p>
+
+<p>Metoda <code>values</code> vrne vse vrednosti, ki so v slovarju. V našem
+ primeru torej telefonske številke. Metodo <code>values</code> človek včasih
+potrebuje, prav pogosto pa ne.</p>
+
+<p>V nasprotju s tem metodo <code>keys</code> potrebujejo samo študenti. Ne vem
+točno, zakaj sploh obstaja. No, vem, zato da študenti lahko pišejo
+<code>for ime in stevilke.keys()</code> namesto
+<code>for ime in stevilke</code>. Druge uporabne vrednosti pa ne vidim. :)</p>
+
+<p>Skratka: ne uporabljajte metode <code>keys</code>.</p>
+
+<p>Slovar ima še dve metodi, ki smo ju videli tudi pri seznamu: metodo, ki
+ sprazni slovar in drugo, ki naredi nov, enak slovar.</p>
+
+<pre>>>> stevilke2 = stevilke.copy()
+>>> stevilke2
+{'Dani': '040 193831', 'Fanči': '040 135367', 'Iva': '040 222333',
+'Helga': '+49 175 4728 475', 'Eva': '051 123123',
+'Berta': '040 318319', 'Ana': '041 310239'}
+>>> stevilke.clear()
+>>> stevilke
+{}
+>>> stevilke2
+{'Dani': '040 193831', 'Fanči': '040 135367', 'Iva': '040 222333',
+'Helga': '+49 175 4728 475', 'Eva': '051 123123',
+'Berta': '040 318319', 'Ana': '041 310239'}</pre>
+
+<p>Omenimo le še eno od slovarjevih metod, <code>get</code>. Ta dela podobno
+ kot indeksiranje, <code>stevilke.get("Ana")</code> naredi isto kot
+ <code>stevilke["Ana"]</code>. Metodo <code>get</code> uporabimo, kadar ni
+ nujno, da je ključ v seznamu in želimo v tem primeru dobiti neko privzeto
+ vrednost. Privzeto vrednost podamo kot drugi argument.</p>
+
+<pre>>>> stevilke.get("Ema", "ni številke")
+'040 584928'
+>>> stevilke.get("Greta", "ni številke")
+'nimam stevilke'</pre>
+
+<p>Še enkrat: ne pišite <code>stevilke.get("Ema")</code>. To je čudno.
+Piše se <code>stevilke["Ema"]</code>. Metodo <code>get</code> uporabite le
+takrat, kadar niste prepričani, da slovar vsebuje ta ključ.</p>
+
+<h4>Primer: kronogrami</h4>
+
+<p>Neka naloga je šla takole.</p>
+
+<p>Veliko latinskih napisov, ki obeležujejo kak pomemben dogodek, je napisanih
+ v obliki <a href="http://en.wikipedia.org/wiki/Chronogram">kronograma</a>:
+ če seštejemo vrednosti črk, ki predstavljajo tudi rimske številke (I=1, V=5,
+ X=10, L=50, C=100, D=500, M=1000), dajo letnico dogodka.</p>
+
+<p>Tako, recimo, napis na cerkvi sv. Jakoba v Opatiji, CVIVS IN HOC RENOVATA
+ LOCO PIA FVLGET IMAGO SIS CVSTOS POPVLI SANCTE IACOBE TVI, da vsoto 1793,
+ ko je bila cerkev prenovljena (o čemer govori napis).</p>
+
+<p>Pri tem obravnavamo vsak znak posebej: v besedil EXCELSIS bi prebrali
+ X + C + L + I = 10 + 100 + 50 + 1 = 161 in ne
+ XC + L + I = 90 + 50 + 1 = 141.</p>
+
+<p>Napiši program, ki izračuna letnico za podani niz.</p>
+
+<p>Očitna rešitev je:</p>
+
+<pre>def kronogram(s):
+ v = 0
+ for c in s:
+ if c=="I":
+ v += 1
+ elif c=="V":
+ v += 5
+ elif c=="X":
+ v += 10
+ elif c=="L":
+ v += 50
+ elif c=="C":
+ v += 100
+ elif c=="D":
+ v += 500
+ elif c=="M":
+ v += 1000
+ return v</pre>
+
+<p>Pri njej vsi, ki poznajo stavek <code>switch</code> oz. <code>case</code>
+postokajo, kako je možno, da Python tega stavka nima. (Pustimo ob strani,
+ali je tole res toliko daljše od <code>switch</code>, sploh če program nespodobno
+nabijemo skupaj:</p>
+<pre>def kronogram(s):
+ v = 0
+ for c in s:
+ if c=="I": v += 1
+ elif c=="V": v += 5
+ elif c=="X": v += 10
+ elif c=="L": v += 50
+ elif c=="C": v += 100
+ elif c=="D": v += 500
+ elif c=="M": v += 1000
+ return v</pre>
+<p>). Ne, nima ga, ker ga skoraj nikoli ne potrebujemo. Tisto, kar delamo z
+njim, pogosto rešimo (tudi) s slovarji.</p>
+
+<p>V slovar si bomo zapisali, katero številko pomeni katera črka.</p>
+
+<pre>stevke = {"I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000}</pre>
+
+<p>Funkcija zdaj deluje tako, da gre prek niza in za vsako črko preveri, ali je v
+slovarju. Če je ni, ne pomeni številke; če je, prištejemo toliko, kolikor je
+vredna.</p>
+
+<pre>def kronogram(s):
+ v = 0
+ for c in s:
+ if c in stevke:
+ v += stevke[c]
+ return v</pre></p>
+
+<p>Še hitreje gre z <code>get</code>; če črke ni, je njena privzeta vrednost 0.
+ </p>
+<pre>def kronogram(s):
+ v = 0
+ for c in s:
+ v += stevke.get(c, 0)
+ return v</pre>
+
+<p>Ob tem si ne moremo kaj, da ne bi poškilili za en mesec naprej, ko se bomo
+ učili funkcijskega programiranja in znali biti še krajši in jedrnatejši,
+ spet predvsem po zaslugi slovarjev.</p>
+
+<pre>def kronogram(s):
+ return sum(stevke.get(c, 0) for c in s)</pre>
+
+
+<h2>Slovarji s privzetimi vrednostmi</h2>
+
+<p>Slovarji so uporabne reči. V veliko primerih pa uporabimo neko različico
+slovarja, ki ima še eno dodatno sposobnost.</p>
+
+<p>Denimo, da smo dobili v preskušanje igralno kocko, za katero nas zanima, ali
+ goljufa. Stokrat smo jo vrgli in zabeležili rezultate.</p>
+
+<pre>meti = [4, 4, 4, 3, 2, 3, 5, 3, 3, 4, 6, 6, 6, 1, 3,
+ 6, 6, 4, 1, 4, 6, 1, 4, 4, 4, 6, 4, 6, 5, 5, 6, 6, 2, 4, 4, 6,
+ 3, 2, 6, 1, 3, 6, 3, 2, 6, 6, 4, 6, 4, 2, 4, 4, 1, 1, 6, 2, 6,
+ 6, 4, 3, 4, 2, 6, 5, 6, 3, 2, 5, 1, 5, 3, 6, 4, 6, 2, 2, 4, 1,
+ 4, 4, 3, 1, 4, 2, 1, 3, 1, 4, 6, 1, 1, 3, 4, 1, 4, 3, 2, 4, 6, 6]</pre>
+
+<p>Zanima nas, kolikokrat je padla katera številka. Nič lažjega. Najprej si
+ pripravimo seznam s sedmimi ničlami.</p>
+
+<pre>>>> kolikokrat = [0] * 7
+>>> kolikokrat
+[0, 0, 0, 0, 0, 0, 0]</pre>
+
+<p>Zdaj nam bo, recimo <code>kolikokrat[3]</code> povedal, kolikokrat je padla
+ trojka. (Čemu sedem? Saj ima kocka samo šest ploskev. Boste videli. Finta.)
+ Zdaj pa štejmo: pojdimo čez vse mete in povečujmo števce.</p>
+
+<pre>>>> for met in meti:
+... kolikokrat[met] += 1
+...
+>>> kolikokrat
+[0, 14, 12, 15, 27, 6, 26]</pre>
+
+<p>(Kje je finta? <code>kolikokrat[0]</code> bo pove, kolikokrat je padla ničla.
+Nikoli pač. Napišite isto reč s seznamom dolžine šest, ne sedem. Ni problem,
+ampak tako, kot smo nardili je preprostejše.)</p>
+
+<p>(Kocka je res videti nekoliko sumljiva: štirke in šestice so nekam pogoste
+ na račun petk. A pustimo statistikom vprašanje, ali je to še lahko
+ naključno ali ne.)</p>
+
+<p>Ups, nalogo smo rešili kar s seznamom! Da, to gre, ker so "predalčki"
+ seznama oštevilčeni, tako kot ploskve kocke. Tole pa ne bo šlo: tule je
+ seznam telefonskih številk deklet, ki jih je danes klical Benjamin. Katero
+ je poklical kolikokrat?</p>
+
+<pre>klici = ['041 103194', '040 193831', '040 318319', '040 193831', '041 310239',
+ '040 318319', '040 318319', '040 318319', '040 193831', '040 193831',
+ '040 193831', '040 193831', '040 193831', '040 318319', '040 318319',
+ '040 318319', '040 193831', '040 318319', '041 103194', '041 103194',
+ '041 310239', '040 193831', '041 103194', '041 310239', '041 310239',
+ '040 193831', '041 310239', '041 103194', '040 193831', '040 318319']</pre>
+
+<p>Za tako velike številke bi moral imeti seznam zelo veliko predalčkov. Še
+ huje bi bilo, če bi namesto seznama številk dobili seznam klicanih oseb.</p>
+
+<pre>klici = ['Cilka', 'Dani', 'Berta', 'Dani', 'Ana', 'Berta', 'Berta',
+ 'Berta', 'Dani', 'Dani', 'Dani', 'Dani', 'Dani', 'Berta', 'Berta',
+ 'Berta', 'Dani', 'Berta', 'Cilka', 'Cilka', 'Ana', 'Dani', 'Cilka',
+ 'Ana', 'Ana', 'Dani', 'Ana', 'Cilka', 'Dani', 'Berta']</pre>
+
+<p>Tu smo s seznamom pogoreli. No, ne čisto; rešitev s seznami seveda obstaja,
+ je pa zoprna - podobna je tistemu, kar smo v začetku počeli z bančnimi
+ računi.</p>
+
+<p>S slovarji je veliko lepše:
+<pre>pogostosti = {}
+for ime in klici:
+ if ime not in pogostosti:
+ pogostosti[ime] = 0
+ pogostosti[ime] += 1
+print(pogostosti)</pre>
+
+<p>Ob vsakem novem klicu preverimo, ali je klicano <code>ime</code> že v
+ slovarju. Če ga ni, da dodamo. Nato - najsibo ime novo ali ne - povečamo
+ števec klicev pri tej osebi.</p>
+
+
+<p>Ker je ta stvar resnično pogosta, nam Python pomaga z modulom
+<code>collections</code>, ki vsebuje podatkovni tip <code>defaultdict</code>.
+(Modul, ki vsebuje podatkovni tip?! Da, da; tudi to je ena od stvari, ki jih
+bomo našli v modulih.) Ta se obnaša tako kot slovar, z eno izjemo: če zahtevamo
+kak element, ki ne obstaja, si ga meni nič tebi nič izmisli. Točneje, doda ga v
+slovar in mu postavi privzeto vrednost. Katero, določimo. Pri tem ne podamo
+privzete vrednosti, temveč "funkcijo", ki bo vračala privzeto vrednost.
+<code>defaultdict</code> bo ustvarjal te, nove vrednosti tako, da bo poklical
+to funkcijo brez argumentov in kot privzeto vrednost uporabil, kar vrne
+funkcija, ki jo v ta namen vsakič sproti pokliče.</p>
+
+<p>Zelo pogosto bo privzeta vrednost 0 in funkcija, ki vrača
+ 0, se imenuje, hm, <code>int</code>.</p>
+
+<p>("Funkcija" <code>int</code>, je vedno sumljivejša in sumljivejša. Že od
+začetka smo v zvezi z njo dajali besedo "funkcija" pod narekovaje, zdaj pa vidimo,
+da zmore vedno več in več stvari. Pa še enako ji je ime kot tipu in funkcij, ki
+jim je ime enako kot tipom, je vedno več. Kakšna skrivnost se skriva za tem? To
+boste izvedeli v enem od prihodnjih napetih nadaljevanj Programiranja 1.)</p>
+
+<p>Preštejmo torej še enkrat Benjaminove klice, tokrat s slovarjem s privzetimi
+ vrednostmi.</p>
+
+<pre>import collections
+
+pogostosti = collections.defaultdict(int)
+for ime in klici:
+ pogostosti[ime] += 1</pre>
+
+<p>Ni to kul?</p>
+
+<p>Poglejmo si nekaj, kar je kul še bolj.</p>
+
+
+<h2>Števec</h2>
+
+<p>Preštevanje je pravzaprav tako pogosta reč, da obstaja zanj specializiran
+ tip. Tako kot <code>defaultdict</code> je v modulu <code>collections</code>,
+imenuje pa se <code>Counter</code>.</p>
+
+<pre>>>> stevilo_klicev = collections.Counter(klici)
+>>> stevilo_klicev
+Counter({'Dani': 11, 'Berta': 9, 'Cilka': 5, 'Ana': 5})</pre>
+
+<p>Komentirali ne bomo veliko, ker še ne znamo. Že ob tem, da sem temu rekel
+ tip, sem se moral ugrizniti v jezik, saj bi raje govoril o razredu. Kaj je
+ in kako deluje, pa nas še presega. Zna pa pravzaprav še veliko stvari,
+ tako da tem, ki jih zanima, priporočam, da si ga ogledajo. Mimogrede:</p>
+
+<pre>>>> napis = "CVIVS IN HOC RENOVATA LOCO PIA FVLGET IMAGO SIS" \
+ "CVSTOS POPVLI SANCTE IACOBE TVI"
+>>> collections.Counter()
+Counter({' ': 13, 'I': 8, 'O': 8, 'V': 7, 'A': 6, 'C': 6, 'S': 6, 'T': 5, 'E': 4,
+'L': 3, 'N': 3, 'P': 3, 'G': 2, 'B': 1, 'F': 1, 'H': 1, 'M': 1, 'R': 1})</pre>
+
+<p>Se pravi, da lahko kronogram rešimo tudi z</p>
+
+<pre>def kronogram(s):
+ crke = collections.Counter(s)
+ return crke["I"] + 5 * crke["V"] + 10 * crke["X"] + 50 * crke["L"] + \
+ 100 * crke["C"] + 500 * crke["D"] + 1000 * crke["M"]</pre>
+
+
+
+<h2>Množice</h2>
+
+<p>Množice so podobne seznamom, a s to razliko, da lahko vsebujejo vsak element
+ samo enkrat. Po drugi strani (in ne le po drugi strani, tudi tehnično) pa
+ so podobne slovarjem. Niso namreč urejene in vsebujejo lahko le elemente,
+ ki so nespremenljivi. Poleg tega pa lahko zelo hitro ugotovimo, ali množica
+ vsebuje določen element ali ne - tako kot lahko pri slovarjih hitro
+ ugotovimo, ali vsebujejo določen ključ ali ne.</p>
+
+<p>Množice zapišemo z zavitimi oklepaji, tako kot smo vajeni pri matematiki.</p>
+<pre>danasnji_klici = {"Ana", "Cilka", "Eva"}</pre>
+
+<p>Tako lahko sestavimo le neprazno množico. Če napišemo le oklepaj in
+ zaklepaj, <code>{}</code>, pa dobimo slovar. (Čemu so se odločili, naj bo
+ to slovar, ne množica? Slovar je bil prej, množice je Python dobil kasneje.
+ Zato.) Če hočemo narediti prazno množico, rečemo</p>
+
+<pre>prazna = set()</pre>
+
+<p>"Funkcija" <code>set</code> je malo podobna "funkciji" <code>int</code>:
+ damo ji lahko različne argumente, pa jih bo spremenila v množico. Damo ji
+ lahko, recimo, seznam, pa bomo dobili množico z vsemi elementi, ki se
+ pojavijo v njem.</p>
+
+<pre>>>> set([1, 2, 3])
+{1, 2, 3}
+>>> set(range(5))
+{0, 1, 2, 3, 4}
+>>> set([6, 42, 1, 3, 1, 1, 6])
+{1, 42, 3, 6}</pre>
+
+<p>Mimogrede opazimo, da tudi množice, tako kot slovarji, res ne dajo nič na
+ vrstni red.</p>
+
+<p>Poleg seznamov lahko množicam podtaknemo karkoli, prek česar bi lahko šli
+ z zanko <code>for</code>, recimo niz ali slovar.</p>
+
+<pre>>>> set("Benjamin")
+{'a', 'B', 'e', 'i', 'j', 'm', 'n'}
+>>> stevilke
+{'Dani': '040 193831', 'Fanči': '040 135367', 'Iva': '040 222333',
+'Helga': '+49 175 4728 475', 'Eva': '051 123123', 'Cilka': '041 103194',
+'Berta': '040 318319', 'Ana': '041 310239'}
+>>> set(stevilke)
+{'Iva', 'Helga', 'Eva', 'Berta', 'Fanči', 'Dani', 'Cilka', 'Ana'}</pre>
+
+<p>Spremenljivka <code>stevilke</code> (še vedno) vsebuje slovar, katerega
+ ključi so imena Benjaminovih oboževalk. Ker zanka prek slovarja "vrača"
+ ključe, bo tudi množica, ki jo sestavimo iz slovarja, vsebovala ključe.</p>
+
+<p>V množico lahko dodajamo elemente in vprašamo se lahko, ali množica vsebuje
+ določen element.</p>
+
+<pre>>>> s = set("Benjamin")
+>>> "e" in s
+True
+>>> "u" in s
+False
+>>> s.add("u")
+>>> s
+{'a', 'B', 'e', 'i', 'j', 'm', 'n', 'u'}
+>>> "u" in s
+True
+>>> s.add("a")
+>>> s.add("a")
+>>> s.add("a")
+>>> s
+{'a', 'B', 'e', 'i', 'j', 'm', 'n', 'u'}</pre>
+
+<p>Na koncu smo poskušali v množico dodati element, ki ga že vsebuje. To seveda
+ ne gre, množica vsak element vsebuje le enkrat.</p>
+
+<p>Če imamo dve množici, lahko izračunamo njuno unijo, presek, razliko...</p>
+
+<pre>>>> u = {1, 2, 3}
+>>> v = {3, 4, 5}
+>>> u | v
+{1, 2, 3, 4, 5}
+>>> u & v
+{3}</pre>
+
+<p>Preverimo lahko tudi, ali je neka množica podmnožica (ali nadmnožica druge).
+ To najpreprosteje storimo kar z operatorji za primerjanje.</p>
+
+<pre>>>> u = {1, 2, 3}
+>>> {1, 2} <= u
+True
+>>> {1, 2, 3, 4} <= u
+False
+>>> {1, 2, 3} <= u
+True
+>>> {1, 2, 3} < u
+False</pre>
+
+<p><code>{1, 2, 3}</code>, je podmnožica <code>u</code>-ja, ni pa njegove
+ <em>prava podmnožica</em>, saj vsebuje kar cel <code>u</code>.</p>
+
+<p>Z množicami je mogoče početi še marsikaj zanimivega - vendar bodi dovolj.</p>
+
+
+<h4>Primer: Seznami v slovarjih</h4>
+
+<p>Recimo, da želimo sestaviti skupine datotek v nekem direktoriju glede na
+ končnice. Sestavili bomo slovar, katerega ključi bodo končnice, na primer
+ .py, .txt in .mp3, vrednosti pri vsakem ključu pa imena datotek s to
+ končnico.</p>
+
+<pre>datoteke = {}
+for ime in os.listdir(dir):
+ konc = os.path.splitext(ime)[1]
+ if not konc in datoteke:
+ datoteke[konc] = set()
+ datoteke[konc].add(ime)</pre>
+
+
+<p>Če ste bili pozorni, niste spregledali, da je gornji program pravzaprav na
+ nek način enak programu, s katerim smo preštevali, kolikokrat je Benjamin
+ klical katero od deklet:
+
+<pre>pogostosti = {}
+for ime in klici:
+ if not ime in pogostosti:
+ pogostosti[ime] = 0
+ pogostosti[ime] += 1</pre>
+</p>
+
+<p>"Istost" je v tem, da obakrat naredimo prazen slovar. Nato gremo z zanko
+<code>for</code> čez neke reči. Za vsako reč (v gornjem primeru datoteke, v
+spodnjem ime dekleta) preverimo, ali je že v slovarju. Če je ni, jo dodamo tako,
+da ji damo neko privzeto vrednost (zgoraj prazno množico, spodaj 0). Nato
+pravkar dodano stvar posodobimo glede na trenutno reč (v gornjem primeru dodamo
+datoteko v pravkar sestavljeno ali od prej obstoječo množico, v spodnjem povečamo
+število klicev te osebe za 1).</p>
+
+<p>Aja, to finto pa že poznamo. Slovarji s privzetimi vrednostmi!</p>
+
+<pre>datoteke = collections.defaultdict(set)
+for ime in os.listdir(dir):
+ konc = os.path.splitext(ime)[1]
+ datoteke[konc].add(ime)</pre>
+</html> \ No newline at end of file