Järjendite omadusi. Ennik
Eelmisel nädalal näitasime, kuidas kontrollida, kas element on järjendis operaatoriga in.
arvud = [1,2,3] if 1 in arvud: print("Olemas!") else: print("Element puudub!")
Nüüd kui teame, et element on olemas, siis saame tema asukoha teada käsuga index:
arvud = [1,2,3] if 1 in arvud: print(f"Elemendi indeks on: {arvud.index(1)}") else: print("Element puudub!")
Siiani oleme järjendi kirjapanekul loetlenud alati kõik tema elemendid. Paraku pole alati võimalik kõiki elemente korraga välja tuua. Appi tuleb järjendite liitmine. Tuletame kõigepealt meelde, mida see tähendas:
>>> [1, 2, 3] + [6, 4, 9] [1, 2, 3, 6, 4, 9] >>> [1] + [2] + [3] [1, 2, 3] >>> [1, 2, 3] + [4] [1, 2, 3, 4] >>> [1] + [2] + [3] + [1, 2, 3] [1, 2, 3, 1, 2, 3] >>> [1] + [] [1] >>> [] + [1] [1]
Sellisel juhul luuakse igakord uus järjend. On olemas ka funktsioon append
, mis lisab olemasoleva järjendi lõppu elemendi. Sarnane on a += [element]
, mis lisab elemendi olemasolevasse järjendisse:
>>> a = [1,2,3] >>> a.append(4) [1,2,3,4]
Enesekontroll
Järjendi filtreerimine
Filtreerimiseks nimetame operatsiooni, mis moodustab mingi järjendi põhjal uue järjendi, milles sisalduvad teatud tingimustele vastavad väärtused algsest järjendist. Eemaldades element või muutes neid. Uuri ja katseta järgnevat näidet:
arvud = [1,2,3,4,5,6,7,8,9,10] for arv in arvud: if arv % 3 == 0: arvud.remove(arv) print(arvud)
Antud näites eemaldati arvud, mis jagusid 3-ga. Käsk remove eemaldab esimese antud elemendi järjendist, ehk ülejäänud sama väärtusega elemendid jäävad järjendisse. Juhul kui sooviksime esimese elemendi alles hoida, ja eemaldada järgneva, siis peaksime kasutama funktsioonid del. See funktsioon kustutab elemendi etteantud indeksil, mis antud näites oleks 2, 5 ja 8.
Enesekontroll
Järjendite kombineerimine
Küllalt sagedasti tuleb ette situatsioon, kus kahest või enamast järjendist on vaja mingi reegli põhjal panna kokku üks järjend. Kõige lihtsam juhtum on see, kus erinevate järjendite elemendid on vaja panna lihtsalt üksteise järele uude järjendisse. Nagu just nägime, saab seda teha järjendite liitmisega. Siin vaatame veidi keerulisemaid probleeme.
Järgnevas näites võtab funktsioon ühend argumendiks kaks järjendit ning tagastab uue järjendi, mis sisaldab mõlema argumentjärjendi erinevaid väärtusi ühekordselt:
def ühend(j1, j2): tulemus = [] for element in j1: if not (element in tulemus): tulemus.append(element) for element in j2: if not (element in tulemus): tulemus.append(element) return tulemus print(ühend([1, 2, 3, 2], [1, 6, 6]))
Lisaks append
-ile on järjenditel veel meetodeid mis ei tagasta midagi, vaid muudavad järjendi sisu. Järgnev tabel näitab, kuidas mõjuvad erinevad meetodid järjendile [3,1,2,3,1,4], mis on salvestatud muutujasse a.
Meetodi rakendamine | Tagastusväärtus | Järjendi uus sisu | Kommentaarid |
---|---|---|---|
a.append(7) | none | [3,1,2,3,1,4,7] | lisab elemendi järjendi lõppu |
a.extend([7,8]) | none | [3,1,2,3,1,4,7,8] | lisab järjenditäie elemente järjendi lõppu |
a.insert(0,34) | none | [34,3,1,2,3,1,4] | lisab näidatud positsioonile näidatud elemendi, järgnevate elementide positsioonid nihkuvad |
a.remove(1) | none | [3,2,3,1,4] | eemaldab esimese näidatud väärtusega elemendi |
a.pop() | 4 | [3,1,2,3,1] | eemaldab viimase elemendi ja tagastab selle |
a.pop(0) | 3 | [1,2,3,1,4] | eemaldab näidatud indeksiga elemendi ja tagastab selle |
a.clear() | none | [] | eemaldab järjendist kõik elemendid |
a.sort() | none | [1,1,2,3,3,4] | sorteerib |
a.reverse() | none | [4,1,3,2,1,3] | pöörab elementide järjekorra ümber |
Nagu näha, tagastab enamik neist meetoditest selle veidra väärtuse None, mis tähendab sisuliselt väärtuse puudumist. Teisti öeldes, neid meetodeid käivitatakse vaid kõrvalefekti pärast. Antud juhul on kõrvalefektiks järjendi muutmine.
Enesekontroll
Muudetavate andmetüüpide omapärad
Järjendi muutmisel või täiendamisel (nii append-i kui a[i] = x puhul) tuleb arvestada ühe omapäraga, mis tuleb ilmsiks siis, kui sama järjend on omistatud mitmele muutujale. Uuri järgnevat näidet ning ennusta, mis antakse selle programmi käivitamisel väljundiks:
a = [1, 2, 3] b = a b.append(4) print(a)
Nagu nägid, ilmus ekraanile [1, 2, 3, 4], ehkki programmist ei paista, et kusagil oleks järjendisse a lisatud arv 4. Selle omapära põhjus peitub real b = a, mis mitte ei kopeeri muutuja a väärtust muutujasse b, vaid hoopis paneb muutuja b viitama samale järjendile. Teisisõnu, b on sama järjendi alternatiivne nimi (ingl alias). Seetõttu, kui järjendit muuta kasutades nime b, on muudatus näha ka nime a kaudu (ja vastupidi).
Seda omapära võib vahepeal ka enda kasuks kasutada. Kui aga soovid parameetrina saadud järjendit arvutuse käigus muuta nii, et funktsioonist väljaspool muutusi näha poleks, siis tuleks teha saadud järjendist koopia ning muudatused teha vaid koopiale. Koopia tegemiseks saab kasutada viilutamise süntaksit, jättes kirjutamata nii vasaku kui parema indeksi. Lisaks saab kasutada meetodit copy:
a = [1, 2, 3] b = a[:] b.append(4) c = a.copy() c.append(4) print(a) # a väärtus on endine
Märkus Kas selline situatsioon, et erinevad muutujad viitavad samale objektile, on võimalik ainult järjendite korral? Tehniliselt võttes ei – muutujad ja harilik (=-ga) omistamine toimivad alati samamoodi hoolimata andmetüübist.
Kõik Pythoni väärtused on programmi käimise ajal esitatud mingite objektidena, mis asuvad kusagil arvuti mälus. Kui käivitatakse lause x = 7, siis luuakse mälus objekt, mis tähistab arvu 7 ja muutujasse x salvestatakse tegelikult ainult viide sellele objektile. Kui me järgmisena käivitame lause y = x, siis muutujasse y salvestatakse sama viit, mis on muutujas x, aga uut täisarvu objekti ei looda. Seega nüüd viitavad muutujad x ja y samale objektile.
Järjendite muutmise video
https://panopto.ut.ee/Panopto/Pages/Viewer.aspx?id=86176b80-ab58-483e-afd8-ac5c00eff523
Enesekontroll
Ennikud
Ennikute omadusi
Paljud enniku omadused on järjendi omadustega üsna sarnased:
- Ennikus on elementide järjestus oluline: (1, 2) ei ole võrdne ennikuga (2, 1).
- Enniku elementide poole saab pöörduda indeksite abil: kui enn on ennik, siis enn[2] on selle enniku kolmas element.
- Enniku pikkuse saame teada funktsiooni
len
abil. - Mingi elemendi ennikusse kuulumist saame kontrollida võtmesõna
in
abil:3 in enn
väärtuseks on kasTrue
võiFalse
. - Funktsioonide
min
jamax
abil saame leida ennikust vastavalt minimaalse või maksimaalse elemendi (eeldusel, et elemendid on mingil moel järjestatavad, nt arvud). - Ennikut saab viilutada:
enn[1:5]
annab alamenniku, milles on enn elemendid indeksitega 1, 2, 3 ja 4.
Siiski pole järjend ja ennik funktsionaalsuse mõttes võrdsed. Enniku kõige olulisem erinevus peitub selles, et see ei ole muudetav (täpsemalt muteeritav, ingl mutable). Ennikusse ei ole pärast selle tekitamist võimalik elemente lisada, neid eemaldada ega muuta, seega pole ennikul näiteks järjendite tuntud käske append
, remove
, pop
, insert
, reverse
ega extend
. Sellest tuleneb, et ennik on alati fikseeritud pikkusega.
Ennikute kasutusalasid
Samuti kasutatakse ennikuid siis, kui funktsioonist on vaja tagastada mitu väärtust. Näiteks see funktsioon leiab kahest järjendist elemendid, mille korrutis on suurim, ja tagastab need elemendid paarina:
def suurim_korrutis(lst1, lst2): suurimad = (0, 0) for el1 in lst1: for el2 in lst2: if el1 * el2 > suurimad[0] * suurimad[1]: suurimad = (el1, el2) return suurimad
Mitme väärtuse tagastamisest
Kui ühe funktsiooni asemel, mis tagastab enniku tulemustest, on võimalik teha mitu funktsiooni, millest igaüks leiab ühe üksiku (väiksema) osa tulemustest, siis on tihti parem stiil valida mitme funktsiooniga variant. Mida väiksemad ülesanded saate eri funktsioonide vahel ära jaotada, seda lihtsam on tavaliselt koodist aru saada, sealt vigu otsida ja seda hallata.
NB! Naljakas eestikeelne nimi on tuletatud sellest, et kolme elemendiga kogumit nimetatakse kolmikuks, nelja elemendiga nelikuks, viiega viisikuks jne. Kui sellises struktuuris on suvaline arv n elementi, siis võiks saadut nimetada nimega n-ik ehk eestipärasemalt ennik.
Enniku video
https://panopto.ut.ee/Panopto/Pages/Viewer.aspx?id=9796a99f-7e9f-4f94-906a-ac5b008036c7