Mitä kone varsinaisesti tekee kohdatessaan listakeräelmän? Miten listakeräelmät "suoritetaan"? Listakeräelmien toimintatapa on itse asiassa varsin suoraviivainen, mutta sen hahmottaminen vaatii hieman harjoitusta.
Yleinen sääntö on, että jos haluaa tietää, mitä listakeräelmäilmaus tekee, pitää lukea se alusta loppuun, paitsi että kaikkein ensimmäiseksi sanottu asia (joka on ennen ensimmäistä for-alilausetta) luetaan viimeiseksi. Valaistaanpa tätä asiaa monimutkaistuvin esimerkein.
[paatepysakki(bussilinja) for bussilinja in linjat]
Kone tekee seuraavasti: se käy läpi linjat-listan siten, että muuttuja bussilinja saa arvokseen kunkin linjat-listan elementin vuorollaan. Tämä on keräelmän for-alilauseen merkitys. Jokaista linjat-listan elementtiä kohden se laskee, mikä on kyseisen bussilinjan päätepysäkki. Tämä on keräelmän alkuosan merkitys. Tulokset kerätään uuteen listaan samassa järjestyksessä kuin bussilinjat olivat linjat-listassa. Tämä uusi lista on listakeräelmän tulos.
On tärkeää ymmärtää, että ilmaus paatepysakki(bussilinja) suoritetaan monta kertaa. Se, minkä linjan bussilinja-muuttuja nimeää, vaihtuu joka suorituskerralla. Tällä tavoin perässä oleva for-alilause ohjaa listakeräelmän suorittamista. Mikäli linjat-lista on tyhjä, paatepysakki-funktiota ei kutsuta kertaakaan, ja tuloksena on tyhjä lista.
[paatepysakki(linja) for linja in linjat if ajetaan(linja, 'lauantai')]
Keräelmässä on kolme osaa (alkuosa, for-alilause ja if-alilause), ja ne vaikuttavat suoritukseen tässä järjestyksessä:
Tuloksena on siis kaikkien lauantaisin ajettavien linjojen päätepysäkit. Tästä huomataan, että for-alilause ohjaa koko toimintaa määräämällä, mille linjoille loput alilauseet ajetaan. if-alilause ohjaa sitä, edetäänkö viimeiseen vaiheeseen eli varsinaiseen keräilyyn.
if-alilauseita voi olla listakeräelmässä vaikka kuinka monta:
[linja for linja in linjat if operoija(linja) == 'HKL' if paatepysakki(linja) == 'Rautatientori']
Luetaan seuraavasti:
Tuloksena on siis lista linjoista, joita ajaa HKL ja joiden päätepysäkki on Rautatientori. Ehdot voisi yhdistää myös yhdeksi if-alilauseeksi (if operoija(linja) == 'HKL' and paatepysakki(linja) == 'Rautatientori').
Samoin for-alilauseita voi olla listakeräelmässä vaikka kuinka monta (tosin aina tarvitaan ainakin yksi, joka "virittää" listakeräelmän):
[[kaupunki, linja] for kaupunki in kaupungit for linja in bussilinjat(kaupunki)]
Mitä kone nyt tekee? Luetaan järjestyksessä.
Tarkastellaan toimintaa vieläkin perusteellisemmin. Olkoot kaupungit = ['Porvoo', 'Pori'], bussilinjat('Porvoo') = [1, 7, 10] ja bussilinjat('Pori') = [1, 2]. Tällöin listakeräelmää suoritettaessa:
Tuloksena on lista [['Porvoo', 1], ['Porvoo', 7], ['Porvoo', 10], ['Pori', 1], ['Pori', 2]].
for- ja if-alilauseita voi olla sekaisin missä tahansa järjestyksessä (paitsi alussa pitää aina olla yksi for-alilause). Esimerkiksi:
[ydin(tavu) for sana in aineisto if mielenkiintoinenko(sana) for tavu in tavut(sana) if suljettuko(tavu)
Tämä tekee seuraavaa:
Tuloksena on lista, jossa on aineiston mielenkiintoisten sanojen suljettujen tavujen ytimet.
Myöhemmän ("sisemmän") for-alilauseen ei tarvitse riippua millään tavoin aiemmasta:
[alku + loppu for alku in ['metsä', 'pelto'] for loppu in ["", 'polku', 'aukea']]
Tässä tapahtuu seuraavaa:
Tuloksena on lista ['metsä', 'metsäpolku', 'metsäaukea', 'pelto', 'peltopolku', 'peltoaukea']. Huomionarvoista (ja erilaista aiempiin tapauksiin nähden) on se, että nyt loppu-muuttujan saamat arvot eivät riipu millään tavoin alku-muuttujan saamista arvoista, vaan listakeräelmä käy läpi jokaisen syötelistojen elementtien yhdistelmän.
Tämä eroaa sekä bussi- että tavuesimerkistä: bussiesimerkissä linjat riippuvat vuorossa olevasta kaupungista ja tavuesimerkissä tavut muodostetaan vuorossa olevasta sanasta.
Pikalinkit: