05 Loeng

Nädala teema: Listid ja sõnastikud Pythonis


“Do not repeat yourself” printsiip

Enne kui hakkame uusi andmestruktuure õppima, meenutame midagi olulist...

Nägite eelmisel nädalal praktikumis, et sama koodi korduvalt kopeerimine on tüütu ja ajakulukas! Ilmselt mõtlesite: "Kas tõesti peab sama asja viis korda kirjutama?"

Õnneks programmeerimises kehtib DRY printsiip nagu te ka kodus lugesite: Don't Repeat Yourself ehk "Ära kordu". See tähendab: kirjuta kood üks kord ja kasuta seda kuus korda!

Mõelge: mitu korda te eelmisel nädalal kirjutasite faili avamise ja sisselugemise koodi? Sama koodi, sama vigu, sama ajakulu. Kirjutage üks kord funktsioon loe_tekst_failist(failinimi) ja kasutage seda igal pool!

See nädal loome eraldi faili ning eraldi funktsioon ning vajadusel toome selle enda programmi sisse ehk impordime. See annab teile:

Aga enne kui hakkame funktsioone importima, vajame uut tööriista - liste. Sest kuidas me muidu hoiame hulka andmeid korraga?


Sissejuhatus – mis asi on list?

Pythonis on list (eesti keeles: järjend) muudetav, järjestatud kogum väärtusi, mida saab töödelda tsüklite, funktsioonide ja operatsioonide abil. Listid on ühed kõige kasulikumad andmestruktuurid, sest nendega saab:

📌 List on nagu vanaema riiul, kuhu saad panna erinevaid asju ritta – sa saad asju juurde panna, välja võtta või ümber tõsta. Purkidel on alati oma kindel järjekord.

List luuakse nurksulgude [ ] abil. Elemendid eraldatakse komadega.

Näiteks:

tühi_list = []
numbrid = [1, 2, 3, 4]
segatud = ["Tere", 42, 3.14, True]

Märkus: programmeerimises loendatakse nullist. Seega list[0] on esimene element ehk antud näitels list[0] = “Tere” ja list[1] on teine ehk list[11] = 42 jne.

Uuendame natukene meie näidet:

# List 0
empty_list = []    # Loome uue listi
print(f"Empty list: {empty_list}") # Prindime muutuja empty_list

# Vaatame mis type on muutuja empty_list
print(f"Empty list type: {type(empty_list)}")

# List 1
numbrid = [1, 2, 3, 4] # Loome uue listi
print(f"List numbrid: {numbrid}") # Prindime muutuja numbrid

# Prindime listis oleva teise elemendi
print(f"List numbrid, index 1: {numbrid[1]}")

# List 2
segatud = ["Tere", 42, 3.14, True] # Loome uue listi
print(f"Segatud list: {segatud}") # Prindime muutuja segatud

# Prindime listis oleva esimese elemendi
print(f"Segatud list, index 0: {segatud[0]}")

# Prindime listis olema viienda elemendi
print(f"Segatud list, index 5: {segatud[5]}")

Näite output:

Empty list: []
Empty list type: <class 'list'>
List numbrid: [1, 2, 3, 4]
List numbrid, index 1: 2
Segatud list: ['Tere', 42, 3.14, True]
Segatud list, index 0: Tere
Traceback (most recent call last):
  File "/Users/gregorkokk/test.py", line 29, in <module>
    print(f"Segatud list, index 5: {segatud[5]}")
                                    ~~~~~~~^^^
IndexError: list index out of range

Näeme, et:

  1. Tühi list - empty_list = [] loob tõepoolest tühja listi ja type() funktsioon kinnitab, et see on <class 'list'>tüüpi.
  1. Numbrite list - numbrid sisaldab nelja elementi: [1, 2, 3, 4]. Kui küsime numbrid[1], saame väärtuse 2, sest Python alustab indekseerimist nullist:
    • Index 0 → 1
    • Index 1 → 2
    • Index 2 → 3
    • Index 3 → 4
  1. Segatud list - segatud sisaldab erinevat tüüpi elemente: string, täisarv, ujukomaarv ja tõeväärtus. segatud[0]annab meile esimese elemendi "Tere".
  1. IndexError - Programm jooksis kokku, kui üritasime pääseda ligi segatud[5] elemendile. See juhtus sellepärast, et:
    • segatud listis on ainult 4 elementi (indeksid 0, 1, 2, 3)
    • Me üritasime pääseda ligi 6. elemendile (index 5)
    • Python viskas IndexError: list index out of range vea, sest sellist indeksit ei eksisteeri

NB!

Listide indekseerimine alustab alati nullist, seega 4-elemendiline list omab indekseid 0, 1, 2, 3.


Põhitegevused listidega

Operatsioonid listi indeksitega

Listi iga elemendi juurde pääseb indeksi kaudu. Pythonis algab indeks nullist, seega esimesele elemendile viitab list[0], teisele list[1] jne. Lisaks saab kasutada negatiivseid indekseid, et liikuda tagantpoolt: list[-1] on viimane, list[-2] eelviimane jne.

a = ["esimene", "teine", "kolmas", "neljas"]

print(a[0])     # "esimene"
print(a[2])     # "kolmas"
print(a[-1])    # "neljas"

Viilutamise näide:

päevad = ["E", "T", "K", "N", "R", "L", "P"]
print(päevad[0])       # "E"
print(päevad[-1])      # Hangime viimane elemendi ehk "P"
print(päevad[-2])      # Hangime eelviimase elemendi "L"
print(päevad[1:4])     # ["T", "K", "N"]
print(päevad[:3])      # ["E", "T", "K"]
print(päevad[4:])      # ["R", "L", "P"]

NB! Kui kasutada viilutamist (slice), siis esimene indeks võetakse arvesse, aga viimast indekst enam ei võeta arvesse!

Muudame viilutamis näidet nii, et prindime esimesed kaks elementi:

päevad = ["E", "T", "K", "N", "R", "L", "P"]
print(päevad[:2])

Mis on selle väljund?

['E', 'T']

Õige vastus on ['E', 'T']

Meetodid listidega

Vaatame, kuidas andmeid lisada ja eemaldada. Loendist andmete eemaldamiseks on mitu võimalust. See, mida kasutate, sõltub olukorrast.

Lisa uus element olemasolevasse järjendisse

Loendiobjektidel on mitu kasulikku sisseehitatud meetodit, millest üks on lisamismeetod ehk append() . Loendile lisamismeetodi kutsumisel lisame objekti loendi lõppu.

Näide append()

my_list = [1, 2]
my_list.append('a')
print(my_list)

my_list.append(4)
print(my_list)

Output append()

[1, 2, 'a']
[1, 2, 'a', 4]

Eemalda konkreetne väärtus järjendist

Kui soovite järjendist konkreetse väärtuse eemaldada, kasutage meetodit remove(). See meetod eemaldab loendist antud objekti esimese esinemise.

Näide remove()

my_list = [1, 2, 3, 2, 5]
my_list.remove(2)
print(my_list)

my_list.remove(2)
print(my_list)

my_list.remove(2)

Output remove()

[1, 3, 2, 5]
[1, 3, 5]
Traceback (most recent call last):
  File "/Users/gregorkokk/test.py", line 8, in <module>
    my_list.remove(2)
    ~~~~~~~~~~~~~~^^^
ValueError: list.remove(x): x not in list

Näeme, et:

  1. append() meetod töötab järjestikku → Iga kord kui kutsume my_list.append(), lisatakse uus element alati listi lõppu:
    • Alguses: [1, 2]
    • Pärast append('a')[1, 2, 'a']
    • Pärast append(4)[1, 2, 'a', 4]
  1. remove() meetod eemaldab ainult esimese leitud väärtuse:
    • Algne list: [1, 2, 3, 2, 5] (sisaldab kahte "2"-te)
    • Esimene remove(2): eemaldab esimese "2" → [1, 3, 2, 5]
    • Teine remove(2): eemaldab järgmise "2" → [1, 3, 5]
    • Kolmas remove(2)VIGA! → listis pole enam ühtegi "2"-te
  1. ValueError tekib, kui üritame eemaldada elementi, mida listis ei ole. Python ütleb: ValueError: list.remove(x): x not in list → see tähendab, et "x" (meie puhul "2") ei leidu enam listist.

NB!

remove() meetod eemaldab alati ainult esimese leitud väärtuse ja viskab vea, kui elementi üldse ei leidu. Kui tahad kõik sama väärtusega elemendid eemaldada, pead remove() meetodit mitu korda kutsuma või kasutama muud lähenemist.

Veel näiteid:

loendid = ["õun", "pirn", "ploom"]
print(loendid[0])      # "õun"
print(loendid[1])      # "pirn"
print(loendid[2])      # "ploom"
print(loendid[-1])     # "ploom"

loendid.append("banaan")  # Lisab lõppu
print(loendid)            # ["õun", "pirn", "ploom", "banaan"]

loendid.remove("pirn")    # Eemaldab esimese esinemise
print(loendid)            # ["õun", "ploom", "banaan"]

Kui remove() ei leia väärtust, viskab see ValueError:

fruits = ["õun", "pirn"]
try:
    fruits.remove("ploom")
except ValueError:
    print("Elemendi eemaldamine ebaõnnestus!")

1. Elementide lisamine loendisse

MeetodKirjeldusNäideMärkus
append(x)Lisab ühe elemendi loendi lõppuloend.append("pirn")Kõige sagedamini kasutatav
extend(iterable)Lisab kõik teise loendi/iteraabli elemendidloend.extend(["õun", "ploom"])Lisab mitu väärtust korraga
insert(i, x)Lisab elemendi kindlale indeksileloend.insert(1, "banaan")Nihutab olemasolevad edasi

2. Elementide eemaldamine loendist

MeetodKirjeldusNäideMärkus
remove(x)Eemaldab esimese esinemise väärtusestloend.remove("pirn")Viga, kui väärtust ei leita (ValueError)
pop(i)Eemaldab ja tagastab elemendi kindlal indeksilloend.pop(1)pop() ilma argumendita eemaldab viimase
del loend[i]Eemaldab elemendi või vahemikudel loend[0:2]Ei tagasta midagi
clear()Tühjendab kogu loendiloend.clear()Loend jääb alles, aga tühi
💡

remove() sobib, kui tead väärtust
pop() või del() sobivad, kui tead asukohta (indeksit)
clear() sobib loendi täielikuks puhastamiseks

3. Sorteerimine ja ümberpööramine

MeetodKirjeldusNäideMärkus
sort()Sorteerib loendi (vaikimisi kasvavalt)loend.sort()Muudab olemasolevat loendit
sort(reverse=True)Sorteerib kahanevas järjekorrasloend.sort(reverse=True)Ainult võrreldavate väärtustega töötab
sorted(loend)Loob uue sorteeritud koopia loendistuus = sorted(loend)Originaal jääb muutmata
reverse()Pöörab elementide järjekorra ümberloend.reverse()Ei sorteeri, ainult peegeldab järjekorra

Listidega kasutamise reeglid

Mis asi on viide mälus?

Pythonis muutujad ei hoia endas mitte otse andmeid, vaid nad viitavad objektidele mälus. Kui sul on list a ja teed b = a, siis mõlemad viitavad täpselt sama mälukoha peale – see tähendab, et kui sa muudad b, siis muutub ka a.
Listide sisemised viited ja koopiad, näide:

a = [1, 2, 3]
b = a        # b ei ole uus list, vaid viide samale listile
b.append(4)

print(f"a: {a}")     # [1, 2, 3, 4] – a muutus ka!
print(f"b: {b}")

Output:

a: [1, 2, 3, 4]
b: [1, 2, 3, 4]

Miks a muutus?

Sest a ja b osutavad täpselt samale listile mälus. Kui muudame b, muudame tegelikult seda ühte ja sama objekti, mida mõlemad kasutavad.

💡

Kuidas viitamine ja mälu töötab?

Arvuti mälu võib ette kujutada kui pikka tänavat numereeritud majadega – igal majal on unikaalne aadress. Igal mälupesal on unikaalne aadress (nt 0x001, 0x002, ..., 0xABC1 jne), mille kaudu arvuti saab andmeid kiiresti leida ja töödelda.

Kui sa kirjutad Pythonis a = [1, 2, 3], siis Python loob listi objekti mälusse, näiteks aadressile 0xABC1. Muutuja a hoiabki seda aadressi — mitte listi sisu, vaid viidet sellele mälupesale. Kui me hiljem kirjutame b = a, siis see ei kopeeri listi, vaid loob uue muutuja b, mis viitab samale aadressile 0xABC1. Nii viitavad mõlemad muutujad samale objektile.

Kui see objekt muutub (nt lisame listile uue elemendi või muudame ühte selle elementi), siis muutus on kohe näha nii akui ka b kaudu, sest nad osutavad samale kohale.

Sellist viitamise mehhanismi kasutatakse Pythonis efektiivsuse pärast. Objektide kopeerimine võtab rohkem aega ja mälu, mistõttu kasutatakse vaikimisi viiteid. Kuid see käitumine võib algajatele vahel segadust tekitada.


Kuidas teha päris koopia?

b = a.copy()  # Teeb uue listi, sama sisuga
# VÕI
b = a[:]      # Slicing teeb uue listi samadest elementidest

Miks need töötavad?


Tehted ja funktsioonid listidega

Lisaks elementide lugemisele ja muutmisele võimaldab Python teha listidega erinevaid tehteid ja kontrollimisi, mis muudavad andmetega töötamise mugavaks ja loogiliseks. Nii saab listi pikendada, korrata, mõõta selle pikkust või kontrollida, kas mingi väärtus on listis olemas.

a = [1, 2]
b = [3, 4]

c = a + b            # [1, 2, 3, 4] – liidab listid kokku
d = a * 3            # [1, 2, 1, 2, 1, 2] – kordab listi kolm korda
pikkus = len(a)      # 2 – elementide arv listis
kas_on_2 = 2 in a    # True – kas väärtus 2 leidub listis

Kasulikud tehted ja funktsioonid:

OperatsioonNäideTulem / Selgitus
Liitminea + bÜhendab kaks listi (teeb uue listi)
Kordaminea * 3Kordab listi mitu korda järjest
Pikkuslen(a)Tagastab elementide arvu
Kuuluvus2 in aTagastab True, kui väärtus leidub listis
Mittekuuluvus5 not in bTrue, kui väärtust pole listis

Selgitus:


List tsüklis

Listid sobivad väga hästi kasutamiseks tsüklitega, eriti for-tsüklis. Sellisel juhul käiakse listi kõik elemendid ükshaaval läbi ning iga tsüklipöörde ajal saab teha vastava elemendiga mingi tegevuse. See on üks kõige sagedamini kasutatavaid mustreid Pythonis.

Näide list tsüklis:

puuviljad = ["õun", "pirn", "ploom"]

for puuvili in puuviljad:
    print(puuvili.upper())

Output list tsüklis:

ÕUN
PIRN
PLOOM

Näeme, et:

Kui vajad ka indeksit, kasuta enumerate():

puuviljad = ["õun", "pirn", "ploom"]

for i, puuvili in enumerate(puuviljad):
    print(f"{i}: {puuvili}")

Output:

0: õun
1: pirn
2: ploom

Näeme, et:


Miks vältida
for i in range(len(list)):

puuviljad = ["õun", "pirn", "ploom"]

# Vähem soovitatav viis:
for i in range(len(puuviljad)):
    print(puuviljad[i])

Miks see pole parim valik?


Kuidas lugeda andmeid tekstifailist listi?

Sul on tekstifail nimed.txt, mille sees on selline sisu:

Mari
Jüri
Kati
Toomas

Lihtne koodinäide

def loe_nimed(failinimi):
    # Avame faili ja loeme kõik read
    with open(failinimi, "r") as f:
        read = f.readlines()

    # Teeme iga rea puhtaks (eemaldame tühikud ja reavahetuse)
    nimed = []
    for rida in read:
        nimi = rida.strip()
        nimed.append(nimi)

    return nimed

def main():
    # Kasutame funktsiooni ja prindime tulemuse
    nimed = loe_nimed(failinimi="nimed.txt")
    print(nimed)

if __name__ == "__main__":
    main()

Output:

['Mari', 'Jüri', 'Kati', 'Toomas']

Näeme, et:


2D listid → listid listis

Pythonis võib list sisaldada teisi liste, mille tulemuseks on mitmemõõtmeline andmestruktuur. Selliseid „listide sees listi“ struktuure kasutatakse näiteks:

Näide ruudustik:

massiiv_ruudustiks = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

Mõtle sellele nagu Exceli tabelile:

[0][0] = 1    [0][1] = 2    [0][2] = 3
[1][0] = 4    [1][1] = 5    [1][2] = 6
[2][0] = 7    [2][1] = 8    [2][2] = 9

Täiustame näide ruudustikku:

massiiv_ruudustiks = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

print(massiiv_ruudustiks)
print(massiiv_ruudustiks[0][2])
print(massiiv_ruudustiks[2][1])

Output:

[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3
8

Näeme, et:

  1. 2D listi struktuur - Kui printisime terve massiiv_ruudustiks, näeme, et Python kuvab selle kui "listi listide sees": [[1, 2, 3], [4, 5, 6], [7, 8, 9]]. Iga sisemine list [1, 2, 3] moodustab ühe "rea" meie ruudustikus.
  1. Topelt-indekseerimine töötab järgmiselt:
    • massiiv_ruudustiks[0][2] → läheme esimesse ritta (index 0) ja sealt kolmandasse veergu (index 2) → saame väärtuse 3
    • massiiv_ruudustiks[2][1] → läheme kolmandasse ritta (index 2) ja sealt teise veergu (index 1) → saame väärtuse 8
  1. Analoogia tabeliga: Mõtle sellele nagu koordinaatidele kaardil:
    • Esimene number [0] ütleb, millises reas me oleme (nagu Exceli rida)
    • Teine number [2] ütleb, millises veerus me oleme (nagu Exceli veerg)
    • [rida][veerg] → [0][2] tähendab "esimene rida, kolmas veerg"

Praktiline ja eluline 2D listi kasutus: Tunniplaan

Näide: Õpilase tunniplaan

esmaspaev = ["Math", "English", "History"]
teisipaev = ["Biology", "PE", "Art"]
kolmapaev = ["Physics", "Chemistry", "Music"]

# Loome 2D listi
opilase_tunniplaan = [
	esmaspaev,
	teisipaev,
	kolmapaev
]

Siin:


Sõnastikud

Sissejuhatus – mis asi on sõnastik?

Pythonis on sõnastik (dict) andmestruktuur, mis seob võtmed (key) väärtustega (value). See on nagu väike andmebaas sinu programmis, kus igal elemendil on nimi (võti) ja sellele vastav väärtus.

Kujutle telefoni kontaktide loendit – igal inimesel on nimi (võti) ja oma telefoninumber (väärtus). Sõnastik võimaldab kiiresti leida õige numbri, ilma kogu nimekirja läbi otsimata.


Sõnastiku loomine ja lugemine

Sõnastik luuakse loogeliste sulgude {} abil. Võtmed ja väärtused eraldatakse kooloniga, paarid omavahel komadega.

kontaktid = {
    "Mari": "555-1234",
    "Jüri": "555-5678",
    "Kati": "555-9999"
}

Kui tahame sõnastikust mingit väärtust kätte saada, saame seda teha järgnevalt:


Meetodid sõnastikega

MeetodKirjeldusNäideMärkus
keys()Tagastab kõik võtmedkontaktid.keys()Saab muuta listiks: list(...)
values()Tagastab kõik väärtusedkontaktid.values()
items()Tagastab kõik (võti, väärtus) paaridkontaktid.items()Kasulik for tsüklis
pop(key)Eemaldab ja tagastab võtmega seotud väärtusekontaktid.pop("Kati")Viga kui puudub
update({...})Lisab või uuendab mitut paari korragakontaktid.update({"Leo": "123", "Mari": "777"})
clear()Tühjendab kogu sõnastikukontaktid.clear()Sõnastik jääb alles, aga tühi
get(key, default)Tagastab väärtuse, kui võti puudub, siis vaikeväärtusekontaktid.get("Anna", "Ei leitud")Turvaline - ei anna viga KeyError viga ehk programm ei jookse kokku

Põhitegevused sõnastikega

Väärtuse lugemine võtme abil:

print(kontaktid["Kati"])  # 555-9999

Elemendi lisamine / muutmine:

kontaktid["Toomas"] = "555-0000"  # Lisab uue
kontaktid["Mari"] = "555-4321"    # Muudab olemasolevat

Elemendi kustutamine:

del kontaktid["Jüri"]


Ligipääs 
.get() abil:

kontaktid = {
    "Mari": "555-1234",
    "Jüri": "555-5678",
    "Kati": "555-9999"
}

# 1. Kontrollimaks, kas võti eksisteerib
if kontaktid.get("Anna") is not None:
    print("Anna number on olemas")
else:
    print("Anna numbrit pole")

# 2. Vaikeväärtusega
telefon = kontaktid.get("Anna", "Pole teada")
print(f"Anna telefon: {telefon}")

# 3. Loendamises (väga kasulik!)
sõnad = ["auto", "kass", "auto", "koer", "auto"]
loendus = {}

for sõna in sõnad:
    # Ilma get()-ta oleks keeruline:
    # if sõna in loendus:
    #     loendus[sõna] += 1
    # else:
    #     loendus[sõna] = 1
    
    # get()-ga lihtne:
    loendus[sõna] = loendus.get(sõna, 0) + 1

print(loendus)  # {'auto': 3, 'kass': 1, 'koer': 1}

Sõnastik tsüklis

kontaktid = {
    "Mari": "555-1234",
    "Jüri": "555-5678",
    "Kati": "555-9999"
}

for nimi, number in kontaktid.items():
    print(f"{nimi} : {number}")

Näeme, et:


Kontrollid ja abifunktsioonid

Kontroll / TeheNäideTulemus
Võti olemas"Mari" in kontaktidTrue
Võti puudub"Peeter" not in kontaktidTrue
Elementide arvlen(kontaktid)3
Koopia tegemineuus = kontaktid.copy()Ei muuda originaali

Sõnastiku näide

Meil on sõnastik, kus on erinevad mängijad, kes teenivad punkte. Me tahame teada palju mingi mängija punkte kokku teenib.

# Mängijad ning nende punktid
punktide_andmed = [
    ("Alice", 10),
    ("Bob", 5),
    ("Alice", 15),  # Alice saab veel punkte
    ("Charlie", 8),
    ("Bob", 3),     # Bob saab veel punkte
    ("Alice", 5)    # Alice saab veel punkte
]

print("Punktide andmise protsess:")
for mangija, punktid in punktide_andmed:
    # get() kasutamine - kui mängijat pole, alusta 0-st
    praegused_punktid = mangijad_punktid.get(mangija, 0)
    uued_punktid = praegused_punktid + punktid
    mangijad_punktid[mangija] = uued_punktid
    
    print(f"  {mangija} sai {punktid} punkti - kokku: {uued_punktid}")

print(f"\nLõplikud tulemused: {mangijad_punktid}")

Sisemised viited ja koopiad

a = {"x": 1}
b = a
b["x"] = 99
print(a)  # {'x': 99}

Nii nagu listide puhul → b = a viitab samale objektile mälus!

Koopia tegemiseks kasuta .copy():

b = a.copy()
b["x"] = 123
print(a)  # Originaal ei muutu

Sõnastik failist

Faili andmed.txt sisu:

Mari:555-1234
Jüri:555-5678

Lugemine sõnastikku:

def loe_kontaktid(failinimi):
    d = {}
    with open(failinimi) as f:
        for rida in f:
            osad = rida.strip().split(":")
            d[osad[0]] = osad[1]
    return d

def main():
    kontaktid = loe_kontaktid("andmed.txt")
    print(f"Kontaktid failist: {kontaktid}")

if __name__ == "__main__":
    main()

Väljund:

Kontaktid failist: {'Mari': '555-1234', 'Jüri': '555-5678'}

Näeme, et:

  1. Faili lugemine rea kaupa - with open(failinimi) as f: avab faili turvaliselt ja for rida in f: loeb iga rea eraldi. See on hea praktika, sest nagu mäletame sulgeb with statement faili automaatselt, isegi kui tekib viga.
  1. Rea töötlemine samm-sammult:
    • rida.strip() eemaldab rea lõpust tühikud ja reavahetuse märgi (\n)
    • split(":") jagab rea kaheks osaks kooloni kohalt → ["Mari", "555-1234"]
    • osad[0] on nimi ("Mari") ja osad[1] on telefoninumber ("555-1234")
  1. Sõnastiku ehitamine - d[osad[0]] = osad[1] lisab sõnastikku uue võtme-väärtuse paari:
    • Võti (key): nimi → "Mari"
    • Väärtus (value): telefoninumber → "555-1234"
  1. Tulemus: Funktsioon tagastab sõnastiku {'Mari': '555-1234', 'Jüri': '555-5678'}, kus nimed on võtmed ja telefoninumbrid on väärtused.
  1. Praktiline kasutus: See meetod on väga kasulik struktureeritud andmete (CSV-sarnased failid) lugemiseks, kus iga rida sisaldab võti-väärtus paari.

    Hiljem saame kiiresti otsida: kontaktid["Mari"] annab meile Mari telefoninumbri.

  1. if __name__ == "__main__": kontroll tagab, et main() funktsioon käivitatakse ainult siis, kui skripti käivitatakse otse, mitte siis kui seda imporditakse teise failist.

Praktiline näide → loenda tegelasi

def loenda_tegelased(tegelased):
    stat = {}
    for t in tegelased:
        stat[t] = stat.get(t, 0) + 1

    return stat


def main():
    multika_tegelased = ["Elsa", "Käsnakalle", "Elsa", "Batman", "Käsnakalle", "Elsa"]

    statistika = loenda_tegelased(tegelased=multika_tegelased)
    print(f"Multika tegelaste statistika: {statistika}")

if __name__ == "__main__":
    main()

Väga levinud muster andmete loendamisel või rühmitamisel!


zip ja .join()

Pythonis on olemas kaks väga kasulikku tööriista, kui töötame korraga mitme listi või sõnesid sisaldava listiga:

Need meetodid muudavad koodi lühemaks, loetavamaks ja aitavad vältida tarbetuid tsükleid.

zip() → mitme listi sidumine

Mis teeb zip?

Näide 1 → nimed ja vanused

nimed = ["Mari", "Jüri", "Kati"]
vanused = [21, 19, 23]

for nimi, vanus in zip(nimed, vanused):
    print(f"{nimi} on {vanus} a.")

Väljund:

Mari on 21 a.
Jüri on 19 a.
Kati on 23 a.

Näide 2 → sõnastiku loomine zip abil

keys = ["eesnimi", "perenimi", "vanus"]
values = ["Mari", "Maasikas", 21]

d = dict(zip(keys, values))
print(d)

Väljund:

{'eesnimi': 'Mari', 'perenimi': 'Maasikas', 'vanus': 21}

Näide 3 → Sõnastiku loomine zip() abil

Kui sul on kaks listi - üks võtmetega ja teine väärtustega - saad neid kombineerida sõnastikuks kasutades dict(zip()) kombinatsiooni.

Kood 1:

# Meil on kaks eraldi listi
opilaste_nimed = ["Mari", "Jüri", "Kati", "Toomas"]
hinded = [5, 4, 5, 3]

# Loome sõnastiku, kus nimi on võti ja hinne on väärtus
hinnete_tabel = dict(zip(opilaste_nimed, hinded))

print("Hinnete tabel:")
print(hinnete_tabel)

# Saame nüüd kiiresti leida üksiku õpilase hinde
print(f"\nMari hinne: {hinnete_tabel['Mari']}")
print(f"Kati hinne: {hinnete_tabel['Kati']}")

Väljund 1:

Hinnete tabel:
{'Mari': 5, 'Jüri': 4, 'Kati': 5, 'Toomas': 3}

Mari hinne: 5
Kati hinne: 5

Kuidas see töötab?

Praktiline kasutus:

# Meil on kaks eraldi listi
opilaste_nimed = ["Mari", "Jüri", "Kati", "Toomas"]
hinded = [5, 4, 5, 3]

# Loome sõnastiku, kus nimi on võti ja hinne on väärtus
hinnete_tabel = dict(zip(opilaste_nimed, hinded))

# Võime ka tsüklis läbi käia
print("\nKõigi õpilaste hinded:")
for nimi, hinne in hinnete_tabel.items():
    print(f"{nimi}: {hinne}")

NB! Kui listid on erineva pikkusega, siis zip() kasutab lühema listi pikkust ja pikem list lõigatakse:

nimed = ["Mari", "Jüri", "Kati"]
hinded = [5, 4, 5, 3, 2]  # Pikem list

tabel = dict(zip(nimed, hinded))
print(tabel)  # {'Mari': 5, 'Jüri': 4, 'Kati': 5}
# Hinded 3 ja 2 jäävad kasutamata!

.join() → stringide ühendamine

Mis teeb .join()?

Näide 1 → nimede loend komadega

nimed = ["Mari", "Jüri", "Kati"]
rida = ", ".join(nimed)
print(rida)

Väljund 1:

Mari, Jüri, Kati

Näide 2 → arvude ühendamine (vajalik map(str, ...))

arvud = [1, 2, 3]
print(" + ".join(map(str, arvud)))

Väljund 2:

1 + 2 + 3

Näide 3 → reavahetusega plokk

read = ["E", "T", "K", "N", "R"]
plokk = "\n".join(read)
print(plokk)

Väljund 3:

E
T
K
N
R

Set → Hulk

Mis asi on set (eesti keeles: hulk) ?

Set / hulk on muudetav, järjestamata ja unikaalsete elementidega andmestruktuur.

Analoogia: peoliste külaliste register – iga nimi saab esineda ainult korra. Järjekord pole tähtis!

Näide:

def main():
    a = {1, 2, 3, 3}
    b = set(["õun", "pirn", "õun"])
    print(a)  # {1, 2, 3}
    print(b)  # {'õun', 'pirn'}

if __name__ == "__main__":
    main()

Põhiomadused

Duplikaadid minema:

def main():
    nimed = ["Mari", "Jüri", "Mari", "Kati"]
    unikaalsed = set(nimed)
    print(unikaalsed)  # {'Mari', 'Jüri', 'Kati'}

if __name__ == "__main__":
    main()


Meetodid (kasulikumad)

MeetodKirjeldusNäideMärkus
add(x)Lisa element hulkas.add("Kati")Ei lisa duplikaati
remove(x)Eemalda elements.remove("Jüri")Vis kab KeyError, kui ei leidu
discard(x)Eemalda, kui leidubs.discard("Mikk")Ei viska viga
pop()Võtab suvalise elemendielem = s.pop()Kuna järjekorda pole
clear()Tühjenda hulks.clear()

Näide:

def main():
    s = {"Mari", "Jüri"}
    s.add("Kati")
    s.discard("Keegi")  # OK, viga ei teki
    try:
        s.remove("Mikk") # KeyError, kui puudub
    except KeyError:
        print("Mikk puudub hulgas")
    print(s)

if __name__ == "__main__":
    main()

Hulgatehted (väga võimsad)

Näide (trenn vs muusikakool):

def main():
    trenn = {"Mari", "Jüri", "Kati", "Toomas"}
    muusikakool = {"Kati", "Toomas", "Anna", "Mikk"}

    print("Kõik lapsed:", trenn | muusikakool)
    print("Mõlemas:", trenn & muusikakool)
    print("Ainult trennis:", trenn - muusikakool)
    print("Ainult muusikakoolis:", muusikakool - trenn)
    print("Ainult ühes:", trenn ^ muusikakool)

if __name__ == "__main__":
    main()

Tuple → Muutumatu järjend

Mis asi on tuple?

Pythonis on tuple (eesti keeles: ennik) muutumatu, järjestatud kogum väärtusi. See on sarnane listiga, kuid peamine erinevus on see, et tuple'it ei saa pärast loomist muuta - see on immutable ehk muutumatu.

Tuple loomine

Tuple luuakse ümarsulgude () abil ning elemendid eraldatakse komadega.

# Tühi tuple
tuhi_tuple = ()

# Tuple numbritega
koordinaadid = (10, 20)

# Tuple erinevate andmetüüpidega
isiku_andmed = ("Mari", 25, True)

# Ühe elemendiga tuple vajab koma!
uks_element = ("ainult_see",)  # Koma on vajalik!

Ühe elemendiga tuple'i puhul on koma kohustuslik, muidu Python ei saa aru, et sa tahad tuple'it teha!

Tuple vs List võrdlus

OmadusTupleList
MuutmineMuutmatuMuudetav
Süntaks(1, 2, 3) [1, 2, 3]
KiirusKiireAeglasem
KasutusKoordinaadid, konfiguratsioonAndmete kogumine
Sõnastiku võtiSobibEi sobi

Tuple kasutamise näited

Näide 1: Koordinaadid

# 2D koordinaadid
punkt = (5, 10)
x, y = punkt  # Tuple unpacking
print(f"X: {x}, Y: {y}")  # X: 5, Y: 10# 3D koordinaadid  
ruumi_punkt = (1, 2, 3)
x, y, z = ruumi_punkt
print(f"Punkt ruumis: ({x}, {y}, {z})")

Näide 2: Funktsioon tagastab tuple

def leia_min_max(arvud):
    """Tagastab tuple koos minimaalse ja maksimaalse väärtusega"""
    return (min(arvud), max(arvud))

numbrid = [5, 2, 8, 1, 9]
miinimum, maksimum = leia_min_max(numbrid)
print(f"Min: {miinimum}, Max: {maksimum}")  # Min: 1, Max: 9

Näide 3: Tuple sõnastiku võtmena

# Malenmäng - ruudud on koordinaatidega
male_laud = {
    (1, 1): "Valge Oda",
    (1, 2): "Valge Ratsu", 
    (8, 8): "Must Kuningas"
}

# Leiame, mis on ruudul (1, 1)
print(male_laud[(1, 1)])  # "Valge Oda"

# List ei sobiks võtmeks - annaks vea!
# male_laud[[1, 1]] = "Test"  # TypeError!

Näide 4: Andmete struktureerimine

# Õpilaste andmed
opilased = [
    ("Mari Maasikas", 20, "Informaatika"),
    ("Jüri Jõhvikas", 19, "Matemaatika"), 
    ("Kati Kask", 21, "Füüsika")
]

print("Õpilaste nimekiri:")
for nimi, vanus, eriala in opilased:
    print(f"  {nimi} ({vanus}a) - {eriala}")

Tuple põhioperatsioonid

andmed = ("Alice", 25, "Tallinn")

# Elementide lugemine (samamoodi nagu listis)
print(andmed[0])    # "Alice"
print(andmed[-1])   # "Tallinn"# Viilutamine
print(andmed[1:])   # (25, "Tallinn")# Pikkuse leidmine
print(len(andmed))  # 3# Kontroll, kas element on olemas
print("Alice" in andmed)  # True

# Aga muutmine ei tööta!
# andmed[0] = "Bob"  
# TypeError: 'tuple' object does not support item assignment

Tuple unpacking (lahtipakkimine)

Tuple unpacking on väga kasulik Python'i omadus:

# Koordinaadid
punkt = (100, 200)
x, y = punkt

# Tuple unpacking
# Funktsioon mis tagastab mitu väärtust
def statistika(arvud):
    return len(arvud), min(arvud), max(arvud), sum(arvud)

andmed = [1, 2, 3, 4, 5]
kogus, miinimum, maksimum, summa = statistika(andmed)

print(f"Elemente: {kogus}")
print(f"Min: {miinimum}, Max: {maksimum}")
print(f"Summa: {summa}")

Millal kasutada tuple'it?

Kasuta tuple'it kui:

Ära kasuta tuple'it kui:

Tuple zip() funktsiooniga

nimed = ["Mari", "Jüri", "Kati"]
vanused = [20, 19, 21]

# zip() loob tuple'eid
for nimi, vanus in zip(nimed, vanused):
    print(f"{nimi} on {vanus} aastat vana")

# Saame ka kõik tuple'd korraga
paarid = list(zip(nimed, vanused))
print(paarid)  # [('Mari', 20), ('Jüri', 19), ('Kati', 21)]

# Nagu näeme on muutuja `paarid` list, mis sisaldab tuple-t
# Teeme selle nüüd hoopis sõnastikuks
paarid = dict(paarid)

# Prindime välja ka
print(paarid)   # {'Mari': 20, 'Jüri': 19, 'Kati': 21}

Väljund:

Mari on 20 aastat vana
Jüri on 19 aastat vana
Kati on 21 aastat vana
[('Mari', 20), ('Jüri', 19), ('Kati', 21)]
{'Mari': 20, 'Jüri': 19, 'Kati': 21}

enumerate() tupletega

Nagu teame, siis enumerate() funktsioon annab meile automaatselt indeksi iga elemendi jaoks. Eriti kasulik on see tuplite listidega töötamisel:

Näide:

# GPS koordinaatide list (tuple'ite list)
gps_punktid = [
    (59.4370, 24.7536),  # Tallinn
    (58.3780, 26.7290),  # Tartu
    (58.2485, 22.4915),  # Kuressaare
    (59.3960, 27.3615)   # Narva
]

print("GPS koordinaadid indeksitega:")
for indeks, (laius, pikkus) in enumerate(gps_punktid):
    print(f"Punkt {indeks + 1}: Laius {laius}°, Pikkus {pikkus}°")

Väljund:

GPS koordinaadid indeksitega:
Punkt 1: Laius 59.437°, Pikkus 24.7536°
Punkt 2: Laius 58.378°, Pikkus 26.729°
Punkt 3: Laius 58.2485°, Pikkus 22.4915°
Punkt 4: Laius 59.396°, Pikkus 27.3615°

Märkused õppijatele:

Kokkuvõte

Tuple on suurepärane valik, kui vajad muutumatuid andmestruktuure. See on kiirem kui list, sobib sõnastiku võtmeks ja aitab vältida juhuslikke andmete muutmisi koodis. Kasuta tuple'it alati, kui tead, et andmed ei muutu!


Kombineeritud näide → nädalaplaan joondatud ridadena

Sageli kasutatakse zip ja .join() koos, et kuvada mitme listi andmed ühtselt vormindatud plokina.

Kood

def treeninguplaan_joondatud(paeva_nimed, km_plaan):
    """Tagastab treeninguplaani mitmerealise stringina."""
    lai = max(len(p) for p in paeva_nimed)  # leia pikima päeva pikkus
    read = [f"{p:} : {d} km" for p, d in zip(paeva_nimed, km_plaan)]
    return "\n".join(read)

def main():
    paevad = ["Esmaspäev", "Teisipäev", "Kolmapäev",
              "Neljapäev", "Reede", "Laupäev", "Pühapäev"]
    km_per_paev = [5, 7, 0, 6, 5, 10, 12]

    plaan = treeninguplaan_joondatud(paevad, km_per_paev)
    print(plaan)

if __name__ == "__main__":
    main()


Väljund

Esmaspäev : 5 km
Teisipäev : 7 km
Kolmapäev : 0 km
Neljapäev : 6 km
Reede : 5 km
Laupäev : 10 km
Pühapäev : 12 km

Kiirvõrdlus → zip vs .join()

MeetodMilleks?NäideMärkus
zip(a, b)Kõrvutada mitut listifor x, y in zip(xs, ys): ...Lõikab lühima järgi
zip(*pairs)Transponeeridaxs, ys = zip(*pairs)Kasulik koordinaatidega
dict(zip())Ehita dict võtmetest ja väärtustestdict(zip(keys, values))Võtmed peavad olema unikaalsed
set.join()Ühendada stringide list, eemaldab dublikaadid", ".join(nimed)Kõik elemendid peavad olema str

Tunni kokkuvõte

Selles loengus õppisime, kuidas kasutada liste ehk järjendeid Pythonis. Listid on paindlikud ja laialdaselt kasutatavad andmestruktuurid, mis võimaldavad hoida mitut väärtust ühes muutujas ning nendega mugavalt töötada.

Kokkuvõttes saime teada:

ListTupleSetDictionary
Kirjapilt[item1, item2, item3] (item1, item2, item3){item1, item2, item3}{key1 : value1
key2 : value2
key3 : value3}
Indekseeritud
(elemendid on järjekorras)
 ❌
Andmed on muudetavad ❌ ❌
Duplikaadid on lubatud ❌ ❌
AnaloogiaInimesed ootavad järjekorras:

- inimesi võib tulla juurde ja minna ära
Isikutunnistus:

- nimi ei muutu
- isikukood ei muutu
Peoliste nimekiri:

- kedagi ei saa olla topelt
- järjekord pole oluline
Sõnaraamat:

Igale sõnale on vastav seletus.

Listid (järjendid):

Dictionary (sõnastik):

Tuple (ennik):