Listojen läpikäynti (for, zip)

Listan läpikäyminen for-silmukan avulla

Kun meillä on tietoja tallennettuna listaan, haluamme yleensä myös hyödyntää niitä. Tätä varten tarvitsemme menetelmän listojen läpikäyntiin. Seuraava tapa ei olisi kovin kätevä, jos listassa olisi tuhat alkiota:

# Muuntokerroin atm -> bar
ATM_TO_BAR = 1.01325

# Määritellään kolme painetta yksiköissä atm
paineet_atm = [0.56, 1.22, 2.34]
# indeksi:      0      1     2

# Muunnetaan paineet bareiksi suoraviivaisesti alkio kerrallaan ja tulostetaan ne
print(round(paineet_atm[0] * ATM_TO_BAR, 3))
print(round(paineet_atm[1] * ATM_TO_BAR, 3))
print(round(paineet_atm[2] * ATM_TO_BAR, 3))

Luonnollisin tapa listojen läpikäyntiin on for-silmukka (johon tutustuimme 1. kierroksella). Listojen kanssa pääsemme toden teolla hyödyntämään for-silmukoita. 

Esimerkki 1
# Muuntokerroin atm -> bar
ATM_TO_BAR = 1.01325

# Määritellään kolme painetta yksiköissä atm:
paineet_atm = [0.56, 1.22, 2.34]
# indeksi:      0      1     2

# Tulostetaan paineet bareina yksi kerrallaan for-silmukan avulla
for paine_atm in paineet_atm:
    paine_bar = paine_atm * ATM_TO_BAR 
    print(f"Paine: {paine_bar:.3f} Pa")

tulostaa

Paine: 0.567 Pa
Paine: 1.236 Pa
Paine: 2.371 Pa

Näin for-silmukan avulla voi käydä läpi helposti listan kaikki alkiot, on niitä sitten kolme tai 3000. Listan läpikäyvän for-silmukan yleinen muoto on siis:

for ALKIO in LISTA:
    print(ALKIO) # silmukassa voimme tehdä alkiolla mitä haluamme
Esimerkki 2

Toteutetaan funktio joka tulostaa kaikki listan kymmenellä jaolliset luvut:

def tulosta_kymmenet(luvut):
    # Funktio saa listan kokonaislukuja, jotka ovat pienempiä kuin 100
    # Funktio tulostaa kaikki kymmenellä jaolliset luvut
    # Funktion paluuarvo on tulostettujen lukujen määrä
    tulostetut = 0
    for luku in luvut:
        if luku % 10 == 0:
            print(luku)
            tulostetut += 1
    return tulostetut
       
tulosta_kymmenet([4, 3, 20, 60, 99])

tulostaa:

20
60
Esimerkki 3

Käydään läpi yhtä listaa ja lisätään samalla alkioita toiseen listaan append-funktiolla:

# Ratkaistaan paine ideaalikaasun tilanyhtälöstä usealle eri tilavuudelle
n = 0.5         # mol
T = 298.15      # K
R = 8.314462618 # J K^-1 mol^-1

# Määritellään kolme tilavuutta yksiköissä m^3
tilavuudet = [0.010, 0.045, 0.105]

# Luodaan tyhjä lista laskettavia paineita varten
paineet = []
# Lasketaan paineet yksiköissä Pa
for tilavuus in tilavuudet:
    paine = n * R * T / tilavuus
    paineet.append(paine)

# Tulostetaan tilavuudet ja paineet yksinkertaisesti ilman pyöristystä
print(f"tilavuudet: {tilavuudet}")
print(f"paineet: {paineet}")

tulostaa

tilavuudet: [0.01, 0.045, 0.105]
paineet: [123947.85147783499, 27543.966995074446, 11804.557283603333]
Esimerkki 4

Tulostetaan tietoja kahdesta yhtä pitkästä listasta. 

Tehdään suoraviivainen for-silmukka, jossa hyödynnetään silmukkamuuttujaa i.

tilavuudet = [0.01, 0.045, 0.105]
paineet = [123947.80946849998, 27543.957659666663, 11804.553282714285]
# Hyödynnetään silmukkamuuttujaa i ja len-funktiota.
# Silmukkamuuttuja i saa siis arvot range(len(paineet)), eli [0, 1, 2]
for i in range(len(paineet)):
    print(f"V = {tilavuudet[i]:.3f} m^3; p = {paineet[i]:.0f} Pa")

tulostaa

V = 0.010 m^3; p = 123948 Pa
V = 0.045 m^3; p = 27544 Pa
V = 0.105 m^3; p = 11805 Pa
Esimerkki 5 

Lasketaan arvoja kolmanteen listaan kahden keskenään yhtä pitkän listan avulla:

ainemaarat = [0.4, 0.6, 0.8]    # mol
tilavuudet = [0.25, 0.25, 0.25] # l
konsentraatiot = []             # Lasketaan konsentraatiot (mol/l)
for i in range(len(ainemaarat)):
    c = ainemaarat[i] / tilavuudet[i]
    konsentraatiot.append(c)
print(konsentraatiot)

tulostaa

[1.6, 2.4, 3.2]

Yllä olevilla suoraviivaisilla for-silmukoilla kurssin tehtävistä selviää täysin hyväksyttävästi. Alla esitellään vielä zip- ja enumerate-funktiot, joilla yllä olevan kaltaiset silmukat on yleensä helpompi toteuttaa.

zip-funktio

Kätevä tapa hoitaa esimerkin 5 tilanne on yhdistää kaksi listaa zip-funktion avulla (engl. zip = vetoketju):

ainemaarat = [0.4, 0.6, 0.8]    # mol
tilavuudet = [0.25, 0.25, 0.25] # l
konsentraatiot = []             # Lasketaan konsentraatiot (mol/l)
for n, V in zip(ainemaarat, tilavuudet):
    # silmukkamuuttuja n saa arvot listasta ainemaarat
    # silmukkamuuttuja V saa arvot istasta tilavuudet
    c = n / V
    konsentraatiot.append(c)
print(konsentraatiot)

Lopputulos olisi sama kuin edellä. Katsotaan tarkemmin, mitä zip-funktio palauttaa (muuntamalla funktion tulos listaksi):

print(list(zip(ainemaarat, tilavuudet)))

tulostaa

[(0.4, 0.25), (0.6, 0.25), (0.8, 0.25)]

Eli kolmen alkion lista, jossa jokainen alkio on kahden alkion monikko (lista, jota ei voi muokata).

zip-funktio on erittäin kätevä tapa yhdistää listoja for-silmukkaa varten.

enumerate-funktio.

enumerate-funktio on myös usein avuksi listojen läpikäymisessä. Se palauttaa kullekin listan alkiolle sekä sen indeksin että alkion arvon:

alkuaineet = ["H", "He", "Li", "Be"]
for indeksi, alkuaine in enumerate(alkuaineet):
    print(f"Z: {(indeksi + 1):d}; alkuaine: {alkuaine:s}")

tulostaa

Z: 1; alkuaine: H
Z: 2; alkuaine: He
Z: 3; alkuaine: Li
Z: 4; alkuaine: Be

Saman silmukan voisi toteuttaa myös yksinkertaisen silmukkamuuttujan avulla:

alkuaineet = ["H", "He", "Li", "Be"]
for i in range(len(alkuaineet)):
    print(f"Z: {(i + 1):d}; alkuaine: {alkuaineet[i]:s}")

On lähinnä makuasia, kumpaa tapaa käyttää. enumerate-funktio voi auttaa tekemään koodista luettavampaa kuin silmukkamuuttujan käyttö. 

Katsotaan vielä tarkemmin, mitä enumerate-funktio oikeastaan palauttaa (muunnetaan enumerate-funktion tulos listaksi):

alkuaineet = ["H", "He", "Li", "Be"]
print(list(enumerate(alkuaineet)))

tulostaa

[(0, 'H'), (1, 'He'), (2, 'Li'), (3, 'Be')]

Eli kukin alkuaineet-listan alkio on saanut parikseen indeksin. Tässä listassa on neljä alkiota ja jokainen alkio on kahden alkion monikko.

Lisätietoa: List comprehension -mekanismi

(Tämä kappale on syventävää tietoa, ei välttämätöntä kurssin läpäisemiseksi)

Kuten ylläolevat esimerkit näyttää, for -silmukka on selkeä työkalu listojen läpikäymiseen ja uusien listojen luomiseen. Mainitsen tässä syventävänä tietona myös List comprehension -mekanismin, jolla Pythonissa on erityisen kätevää luoda uusia listoja olemassaolevien listojen avulla.

List comprehension-lauseke kirjoitetaan hakasulkeiden väliin:

uusi_lista = [ uuden_listan_alkion_lauseke for vanha_alkio in vanha_lista ]

Esimerkki:

tilavuudet_m3 = [0.010, 0.045, 0.105]
tilavuudet_litroina = [ tilavuus_m3 * 1000 for tilavuus_m3 in tilavuudet_m3 ]
print(tilavuudet_m3)
print(tilavuudet_litroina)

tulostaa

[0.01, 0.045, 0.105]
[10.0, 45.0, 105.0]
Toinen esimerkki:

# Ratkaistaan paine ideaalikaasun tilanyhtälöstä usealle eri tilavuudelle
n = 0.5         # mol
T = 298.15      # K
R = 8.314462618 # J K^-1 mol^-1

# Määritellään kolme tilavuutta yksiköissä m^3
tilavuudet = [0.010, 0.045, 0.105]

# Käytetään for-silmukan sijasta "List comprehension"-mekanismia
paineet = [ n * R * T / tilavuus for tilavuus in tilavuudet ]

# Tulostetaan tilavuudet ja paineet yksinkertaisesti ilman pyöristystä
print("tilavuudet:", tilavuudet)
print("paineet:", paineet)

tulostaa

tilavuudet: [0.01, 0.045, 0.105]
paineet: [123947.85147783499, 27543.966995074446, 11804.557283603333]

Tehtävä 3.4.1.