Institute of Computer Science
  1. Courses
  2. 2025/26 fall
  3. Computer Programming (LTAT.03.001)
ET
Log in

Computer Programming 2025/26 fall

  • Üldinfo
  • 1. Muutuja ja avaldis
  • 2. Tingimuslause
  • 3. Funktsioon
  • 4. Korduslause
  • 5. Sõned. Lihtsam failitöötlus
  • 6. Kontrolltöö 1
  • 7. Järjend
  • 8. Järjend 2
  • 9. Kahekordne tsükkel. Failitöötlus
9.1 Kahekordne tsükkel. Failitöötlus
9.2 Kodutöö
9.3 Harjutused
9.4 Silmaring: NumPy
  • 10. Andmestruktuurid
  • 11. Andmestruktuurid 2
  • 12. Kontrolltöö 2
  • 13. Objektorienteeritud programmeerimine
  • 14. Objektorienteeritud programmeerimine 2
  • 15. Rekursioon
  • 16. Kordamine. Projektide esitlused
  • Viiteid
  • Silmaringimaterjalid
  • Materjalid

Kahekordne tsükkel. Failitöötlus

Järjend tsüklis

Kui maatriks on esitatud kahemõõtmelise järjendina, siis märkame, et maatriksi iga rida on omakorda eraldi järjend, veerg aga ei ole. Tegelikult saame isegi programmikoodis maatriksi ridu loetavalt välja tuua:

tabel = [
    [1, 2, 4],
    [1, 5, 0]
]

Kui see tabel ekraanile väljastada (print(tabel)), siis ilmub tabel ühele reale pressituna:

[[1, 2, 4], [1, 5, 0]]

Tabelikujulise väljundi jaoks võime väljastada tsükli abil iga rea eraldi:

Näiteprogramm. Kahemõõtmelise järjendi sisemiste järjendite printimine

tabel = [ [1, 2, 4], [1, 5, 0] ]
for rida in tabel:
    print(rida)

See programm väljastab:

[1, 2, 4]
[1, 5, 0]

Tsükli igal sammul väljastatakse üks rida järjendina ekraanile. Varasemast teame, et kui tahame iga elemendi ükshaaval järjendist väljastada, siis seda saab teha tsükli abil nii:

for element in rida:
    print(element)

Need konstruktsioonid saab omavahel kokku panna nii, et iga rea korral väljastatakse kõik selle rea elemendid ükshaaval:

Näiteprogramm. Kahemõõtmelise järjendi sisemiste elementide printimine

tabel = [ [1, 2, 4], [1, 5, 0] ]
for rida in tabel:
    for element in rida:
        print(element)

See programm väljastab:

1
2
4
1
5
0

Siin teeb sisemine tsükkel kogu oma töö ära igal välimise tsükli sammul. Niimoodi kokku pandud tsükleid võib nimetada kahekordseks tsükliks.

Eelmise näiteprogrammi abil saame tõesti kõik elemendid maatriksist (või kahekordsest järjendist) väljastada, kuid tegelikult ei ilmu nad ekraanile siiski tabelina. Põhjus on selles, et funktsioon print väljastab pärast igat väljakutset lisaks elemendile ka reavahetuse. Seda käitumist saab muuta, kui anda print funktsioonile nimelise argumendina nimega end ette sõne, mis tuleb alati lõpuks väljastada.

for rida in tabel:
    for element in rida:
        print(element, end=" ")

Selle programmijupi käivitamisel ilmuvad elementide vahele reavahetuste asemel tühikud. Samuti võiks me end=" " asemel kirjutada näiteks end="", et elementide vahele pandaks tühjad sõned (ehk ei pandaks mitte midagi) või hoopis midagi muud – kõik sõned on sinna lubatud. Huvi korral saate rohkem lugeda funktsiooni print võimaluste kohta Pythoni dokumentatsioonist.

Sellist programmi käivitades ilmuvad elemendid küll ilusate vahedega, kuid erinevate ridade elemendid väljastatakse ikkagi samale reale. Selle parandamiseks saame väljastada tavalise print funktsiooniga ühe reavahetuse iga kord, kui minnakse elementide vaatamisel järgmise rea juurde: Näiteprogramm. Kahemõõtmelise järjendi ilus printimine

tabel = [ [1, 2, 4], [1, 5, 0] ]
for rida in tabel:
    for element in rida:
        print(element, end=" ")
    print()

See programm väljastab:

1 2 4 
1 5 0

Siin on reavahetust väljastav print just välimise tsükli sees, mitte sisemise. Nii rakendub see ainult siis, kui sisemine tsükkel on kõik mingi rea elemendid (tühikutega eraldatult) väljastanud ja välimisel tsüklil on aeg minna järgmise rea (välimise tsükli uue sammu) juurde.

Kui tahame arvestada ka asjaolu, et elemendid võivad tabelis olla erineva pikkusega, siis võib tühiku asemel kasutada tabulatsioonimärki "\t" või huvi korral uurida käsu rjust kohta.

Tsükkel ja indeksid

Eespool kasutasime Pythoni mugavaid for-tsükli võimalusi, et järjendit elementhaaval läbida ilma indeksite peale mõtlemata. Sageli on aga vaja tegeleda ainult teatud kohtadel paiknevate elementidega ja sellisel juhul on kasu indeksitest. Järgmises programmis kasutame indekseid, et järjendist elemente kätte saada:

Näiteprogramm. Järjendi läbimine indeksi põhjal

a = [1, 6, 3, 2, 1, 8, 3, 2]
for i in range(len(a)):
    print(i)

Funktsiooni range abil omandab tsüklimuutuja i järjest väärtusi lõigust 0 kuni len(a) - 1 . Sellisel juhul saab muutuja i väärtuseks järjest 0, 1, 2, 3, 4, 5, 6 ja 7.

Kahekordne tsükkel ja indeksid

Samuti saame indeksite abil läbida kahekordseid järjendeid. Siis võetakse sageli (aga mitte kohustuslikult) tsüklimuutujateks i ja j. Tabeli väljastamise saaksime indeksite abiga teha nii:

for i in range(len(tabel)):
    for j in range(len(tabel[i])):
        print(tabel[i][j], end=" ")
    print()

Välimine tsükkel käib ikka ridahaaval, i saab väärtusi lõigust 0 kuni len(tabel)-1. Sisemine tsükkel võtab tol hetkel vaadeldava rea (tabel[i]) elemente (tabel[i][j]) vastavalt j väärtustele, järjest 0 kuni len(tabel[i])-1. See programm töötab ka siis, kui read ei ole ühepikkused – iga rea korral muutub j just vastavalt konkreetse rea pikkusele.

Vahel on vaja teada, kus teatud tingimustele vastav element paikneb. Järgmine programm väljastab ekraanile negatiivsete arvude asukohad (indeksid):

Näiteprogramm. Negatiivsete arvude indeksid

tabel = [[1, -4, 5], [-4, 6, 7], [5, 6, -7]]
for i in range(len(tabel)): # ridade kaupa
    for j in range(len(tabel[i])): # selle rea elementide kaupa
        if tabel[i][j] < 0:
            print("Negatiivne arv " + str(tabel[i][j]) +
                  " on kohal (" + str(i) + "; " + str(j) + ").")

Kahekordsed tsüklid

Mõiste kahekordne tsükkel tähendab, et ühe tsükli sees kasutatakse teist tsüklit. Seda võime näiteks kasutada, et saada mingist mitmetasemelisest järjendist elemendid eraldi kätte.

Kui me kujutame, et meil on kiviviskevõistlus, kus on 3 viset. Iga võistleja tulemused pannakse järjendisse, mis omakorda liidetakse kõikide skoori järjendisse. Võistluse lõpuks peame need kuidagi arusaadavalt väljastama.

skoor = [[34, 28, 29],[31, 36, 33],[30, 33, 32]]
luger = 0
for võistleja in skoor:
    kokku = 0
    luger += 1
    print("Võistleja " + str(luger) + " visked olid: ")
    for vise in võistleja:
        kokku += vise
        print(vise)
    print("Tema visked kokku olid: " + str(kokku))

Proovi läbi teha. Kas seda saaks lahendada ka ühe tsükliga?

Nagu selgub, siis kahemõõtmelistel järjenditel on vaja kahte indeksit, et elementi kätte saada. Kui me proovime järjendi elementi kätte saada indeksilt 0, siis selleks elemendiks on teine järjend [34, 28, 29]. Nüüd peame veel lisaks kirjutama, et tahame sellest järjendist elementi indeksil 0. Seda saab koodis kirjutada nii:

esimeneElement = skoor[0][0]

Seda ülesannet saaks lahendada ka ühe tükliga, sest teame, et iga võistleja tegi täpselt 3 viset. Kui visete arv erineks, siis ei oleks see enam nii kerge.

Kahekordset tsüklit võib vaja minna veel ka siis, kui soovime leida teatud omadusega elementide paare. Näiteks kui meile on antud järjend ja soovime sealt leida arvud, mille summa on täpselt 10. Seda saab lahendada nii:

a = [1,2,3,4,5,6,7,8,9]
for i in a:
    for j in a:
        if i + j == 10:
            print(str(i) + "+" + str(j) + " = 10")

Proovi seda programm enda järjendiga.

Video

https://panopto.ut.ee/Panopto/Pages/Viewer.aspx?id=2035ee3f-3635-4d74-8545-ac5c008a0d36

Enesekontroll

Enesekontroll

Järjend ja funktsioon

Järjend funktsiooni argumendina

Programmide kirjutamisel on mõistlik püüda tööd jaotada erinevateks osadeks – alamprogrammideks ehk funktsioonideks.

Pythonis on juba mitmeid defineeritud funktsioone, millele saab anda argumendiks järjendi, näiteks max, min ja len. Ka funktsioonile print saab anda argumendiks järjendi.

a = [2, -3, 5, 1]
print(max(a))
print(min(a))
print(len(a))
print(a)

Järgmine funktsioon kontrollib, kas esimese argumendina antud järjendis on elemente, mis on suuremad teisest argumendist. Kui on, siis tagastatakse tõeväärtus True ja kui pole, siis tõeväärtus False:

def on_suuremaid(jarjend, piir):
    for i in range(len(jarjend)):
        if jarjend[i] > piir:
            return True
    return False

Oluline on tähele panna, et piirist suuremate elementide puudumist (return False) tohib kinnitada alles siis, kui kõik elemendid on läbi vaadatud. Leidumist saame kinnitada kohe, kui sellise elemendi leiame.

Pane tähele, et tegelikult saaks sama ülesannet lihtsamini lahendada funktsiooni max abil. Kui järjendi maksimaalne element on piirist suurem, siis on tulemus True, vastasel juhul False:

def on_suuremaid(jarjend, piir):
    return max(jarjend) > piir

Funktsioonina võime realiseerida ka mõne varemtoodud konstruktsiooni. Tabelit väljastava funktsiooni puhul ei tagastata midagi (täpsemalt tagastatakse None). See-eest toimub funktsiooni sees ekraanile väljastamine:

Näiteprogramm. Funktsiooniga väljastamine

def valjasta_tabel(tabel):
    for i in range(len(tabel)):
        for j in range(len(tabel[i])):
            print(tabel[i][j], end=" ")
        print()


arvude_tabel = [[1, 3, 5], [4, 6, 6], [3, 6, -3]]
valjasta_tabel(arvude_tabel)
print()
arvude_tabel2 = [[-1, 3, 5], [4, -8, 6]]
valjasta_tabel(arvude_tabel2)
print()
riimitabel = [['karu', 'maru', 'taru'], ['haru', 'varu', 'naru']]
valjasta_tabel(riimitabel)

Loomulikult võib funktsioon ka mingi väärtuse tagastada. Näiteks võib loendada, mitu positiivset elementi on etteantud tabeli (esimene argument) etteantud indeksiga (teine argument) veerus:

def positiivsete_arv_veerus(tabel, veeru_indeks):
    loendaja = 0
    for rida in tabel:
        if rida[veeru_indeks] > 0:
            loendaja += 1
    return loendaja

Järjend funktsiooni väärtusena

Funktsioon võib tagastada järjendi, mis võib olla kahemõõtmeline (või rohkemgi).

Koostame funktsiooni loo_diagonaalmaatriks(n), mille argumendi n väärtus näitab, kui suur ruutmaatriks tehakse. Maatriksi peadiagonaali elementidele anname väärtuse 1 ja kõikjale mujale väärtuse 0. Näiteks väljakutsumine loo_diagonaalmaatriks(3) peaks tagastama 1, 0, 0], [0, 1, 0], [0, 0, 1?. Kasutame ära teadmist, et peadiagonaali element on parajasti selline, mille rea- ja veeruindeks on võrdsed:

def loo_diagonaalmaatriks(n):
    maatriks = []
    for i in range(n):       # välimine tsükkel tekitab ridu
        rida = []
        for j in range(n):   # sisemine hoolitseb iga rea täitmise eest
            if i == j:          # tegemist on peadiagonaali elemendiga
                rida.append(1)
            else:
                rida.append(0)
        maatriks.append(rida)
    return maatriks

Proovi funktsiooni täiendada nii, et sellele antakse ka teine argument, mille väärtus kirjutatakse 1 asemel peadiagonaali elementideks.

Failist järjendisse lugemine

Seni oleme tegutsenud kahemõõtmeliste järjenditega, mille elemendid kirjutasime programmiteksti sisse, näiteks:

tabel = [[1, 2, 4], [-1, 5, 0]]

või otse käsureal funktsioonile argumente andes, näiteks:

>>> on_bingo_tabel([[1, 30, 34, 55, 75], [10, 16, 40, 50, 67], [5, 20, 38, 48, 61], [4, 26, 43, 49, 70], [15, 17, 33, 51, 66]])

Vähegi suuremate mahtude juures on see ebamugav ja praktikas ka tihti võimatu, sest tahame sama programmi abil töödelda palju erinevaid andmeid. Failist lugemist käsitlesime varem. Nüüd vaatame, kuidas failist andmed mugavalt kahemõõtmelisse järjendisse saada.

Olgu näiteks õpilaste saadud (täisarvulised) punktid tühikutega eraldatult failis, igal real ühe õpilase punktid. Näiteks:

1 4 5
3 6 8
2 4 8
10 5 0

Kahemõõtmelisse järjendisse saab need andmed näiteks nii: punktide_tabel = []

for rida in fail:  # iga rea jaoks failist
    op_punktid = []  # kogume ühe õpilase punkte
    osad = rida.split() # tühikute kohalt osadeks
    for osa in osad:  # osade kaupa
        op_punktid.append(int(osa)) # järjekordsed punktid juurde

    punktide_tabel.append(op_punktid) # õpilase punktide järjend juurde

Eraldusmärgid andmetes

Eelmises näites olid ühel real olevad andmed eraldatud tühikutega. Ajalooliselt on eraldajaks olnud näiteks koma. Sellest tuleb ka levinud failiformaadi lühend CSV – ingl Comma-separated values. Tegelikult ei pruugi koma alati hästi eraldajaks sobida, kuna võib andmetes tähendada midagi muud, näiteks komadega arve. Levinumad eraldajad on tabulatsioonimärk "\t" ja semikoolon.


Kasutatud allikad:

  • https://progeopik.cs.ut.ee/
  • https://web.htk.tlu.ee/digitaru/programmeerimine/
  • https://web.htk.tlu.ee/digitaru/tarkvara2/
  • Institute of Computer Science
  • Faculty of Science and Technology
  • University of Tartu
In case of technical problems or questions write to:

Contact the course organizers with the organizational and course content questions.
The proprietary copyrights of educational materials belong to the University of Tartu. The use of educational materials is permitted for the purposes and under the conditions provided for in the copyright law for the free use of a work. When using educational materials, the user is obligated to give credit to the author of the educational materials.
The use of educational materials for other purposes is allowed only with the prior written consent of the University of Tartu.
Terms of use for the Courses environment