Tapaaminen 21.01.2010

Aiheina:

  • merkkijono
  • lista
  • for-silmukka

Linkkejä:

Merkkijono

Yhdistetyt tietotyypit

Tähän mennessä käyttämistämme tietotyypeistä merkkijono, eli str, eli string poikkeaa muista (int, bool, float) siinä, että merkkijono koostuu osista, yksittäisistä merkeistä. Tietotyyppejä, jotka koostuvat osasista, kutsutaan yhdistetyiksi tietotyypeiksi. Tällasen tyypin esiintymää voidaan kohdella yhtenä yksikköinä taikka käsitellä sen sisältämiä osasia.

Merkkijonon yksittäiseen kirjaimeen voidaan viitata hakasuljemerkinnällä:

>>> fruit = "banaani"
>>> letter = fruit[1]
>>> print letter
a

Yllättikö tulos? Pythonissa, kuten niin monessa muussakin ohjelmointikielessä jonossa, myös merkkijonossa, olevien alkioiden numerointi alkaa nollasta. Näin siis merkkijonon fruit nollas kirjain on ‘b’, yhdes kirjain ‘a’, kahdes kirjain ’n’, kolmes kirjain ‘a’ ja niin edelleen.

Merkkijonon paikkaan viittaavasta kokonaisluvusta käytetään nimitystä indeksi.

Merkkijonon pituuden saa selville funktiolla len()

>>> len(fruit)
7

Tässä kohtaa on jälleen huomattavaa, että merkkijonon ‘banaani’ indeksit käyvät luvusta 0 lukuun 6 ja sen pituus on 7. Merkkijonon viimeiseen kirjaimeen ei siis voi viitata kirjoittamalla fruit[len(fruit)]

>>> fruit[len(fruit)]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: string index out of range

Viittausta ei voitu tehdä, koska yritettiin etsiä kirjainta sanan ‘banaani’ lopun tuolta puolen. Sanan viimeistä kirjainta haettaessa täytyy indeksiksi siis valita len(fruit)-1

>>> fruit[len(fruit)-1]
'i'

Saman saavuttamiseen voidaan käyttää myös negatiivista indeksiä: fruit[-1]. Vastaavasti toiseksi viimeinen merkki löytyy käyttämällä indeksiä -2: fruit[-2]

Jonon läpikäynti ja for-silmukka

Toisinaan on tarpeellista käydä läpi merkkijono kirjain kerrallaan. Käyttämällä while-silmukkaa tämä läpikäynti voidaan tehdä seuraavasti:

index = 0
while index < len(fruit):
    letter = fruit[index]
    print letter
    index += 1

Tämä silmukka aloittaa indeksillä 0, tutkii merkkijonoa fruit niin kauan kuin ei olla merkkijonon lopussa ja tulostaa merkkijonon kirjain kerrallaan. Kullakin kierroksella index-muuttujaa kasvatetaan, jotta päästään eteen päin. Silmukka siis päättyy, kun merkkijonon fruit viimeinen kirjain indeksillä len(fruit)-1 on tulostettu ja index-muuttujan arvoksi on saatu len(fruit).

Toinen vaihtoehto tämän tehtävän suorittamiseksi on for-silmukka, joka Pythonissa toimii tähän käyttöön erittäin sopivalla ja elegantilla tavalla:

for letter in fruit:
     print letter

Esimerkki for-silmukan käytöstä:

prefixes = "JKLMNOPQ"
suffix = "ack"
for letter in prefixes:
    print letter + suffix

Merkkijonossa prefixes on lueteltu kakki mahdolliset aloituskirjaimet ja merkkijonossa suffix yhteinen loppuosa. For-silmukassa käydään läpi kaikki aloituskirjaimet ja katenoidaan kunkin perään yhteinen loppuosa ja tulostetaan saatu merkkijono. Lopputulos näyttää tältä:

Jack
Kack
Lack
Mack
Nack
Oack
Pack
Qack

Merkkijonon viipalointi

Merkkijonosta voidaan viipaloida paloja eli kopioida pätkiä alkaen jostain kohdasta johonkin kohtaan saakka.

>>> s = "Peter, Paul, and Mary"
>>> print s[0:5]
Peter
>>> print s[7:11]
Paul
>>> print s[17:21]
Mary

Viipalointi tapahtuu vastaavalla hakasuljemerkinnällä kuin yksittäiseen merkkiin viittaaminen, mutta käyttämällä kahta ’:’-merkillä erotettua indeksiä. Ensimmäinen indeksi tarkoittaa ensimmäistä mukaan otettavaa merkkiä ja jälkimmäinen ensimmäistä, jota ei oteta mukaan. Tämän viittauksen ymmärtämistä voidaan helpottaa ajattelemalla, että indeksi viittaakin aina kahden merkkijonossa olevan merkin väliä. Tällöin indeksi 0 tarkoittaa paikkaa ennen merkkijonon alkua, indeksi 1 ensimmäistä kirjainten väliä, 2 toista kirjainväliä jne. Tällöin merkintä s[m:n] tarkoittaa siis merkkijonoa, joka saadaan leikkaamalla merkkijono s väleistä m ja n. Lisäksi viipaloimalla saadun merkkijonon pituus saadaan yksinkertaisesti vähennyslaskuna n-m.

Viipaloinnissa voidaan myös jättää toinen tai molemmat indeksit pois. Tällöin viipaloinnin rajoina käytetään merkkijonon alkua ja loppua. Esimerkiksi:

>>> print s[7:]
Paul, and Mary
>>> print s[:5]
Peter
print s[:]
Peter, Paul, and Mary

Vertailu

Yhtäsuuruusvertailu == vertaa, ovatko merkkijonot samat merkki merkiltä.

>>> "banaani" == "bana" + "ani"
True

Pienemmyys- ja suuremmuusvertailut on määritelty merkkijonoille sanakirjajärjestyksen avulla. Tässä tulee kuitenkin huomata, että Pythonille pienet ja suuret kirjaimet ovat eri merkkejä ja pieni kirjain on aina suurempi kuin vastaava suuri kirjain.

if word < "banana":
    print "Your word," + word + ", comes before banana."
elif word > "banana":
    print "Your word," + word + ", comes after banana."
else:
    print "Yes, we have no bananas!"

Sekä

>>> 'Zebra'<'banana'
True

Merkkijono on muuttamaton

Merkkijono on tietotyyppinä muuttamaton (immutable). Tämä tarkoittaa sitä, että merkkijonon yksittäistä kirjainta ei voi muuttaa sijoittamalla uutta kirjainta johonkin paikkaan esimerkiksi kirjoittamalla: fruit[3] = ‘X’. Tämän sijaan, jos halutaan uusi muunnelma aiemmasta merkkijonosta, tämä voidaan rakentaa esimerkiksi viipaloinnin avulla:

>>> fruitti = fruit[:3] + 'X' + fruit[4:]
>>> print fruitti
banXani

in-operaattori

Pythonissa on helppoa testata, sisältyykö joku merkkijono toiseen merkkijonoon. (ääritapauksessa yksittäinen kirjain tai koko merkkijono) Tähän käytetään in-operaattoria, jonka syntaksi on varsin looginen:

>>> 'p' in 'apple'
True
>>> 'i' in 'apple'
False
>>> 'ap' in 'apple'
True
>>> 'pa' in 'apple'
False

Lisää yksityiskohtia merkkijonoista kirjan kappaleessa 7.

Lista

Lista on toiminnaltaan hyvin samanlainen kuin merkkijono, mutta yleisempi, sillä sen osina voi olla mitä tahansa alkioita. Samoin kuin merkkijono, lista on myös järjestetty jakso yksittäisiä alkioita ja alkioihin voidaan viitata nollasta alkavalla indeksillä.

Listan alkiot

Lista voidaan luoda useammallakin tavalla. Yksinkertainen tapa on vain luetella listan alkiot hakasulkeisiin suljettuina ja pilkulla eroteltuina.

[10,20,30,40,50,60]
['aarne','bertta','celsius','daavid']

Listassa voi olla myös keskenään erityyppisiä alkioita. Myös listoja.

[20, 'aarne', True, [2,3,'Tero', 0.5], 40]

Sisäkkäisten listojen tapauksessa sisällä olevaa listaa käsitellään ulomman listan yhtenä alkiona.

Erikoistapauksena on tyhjä lista [], jossa ei ole lainkaan alkioita. Tyhjä alkio, samoin kuin kokonaisluku 0 ja tyhjä merkkijono ‘’, tulkitaan tarvittaessa boolen-arvoksi False. Tämä on käytännöllistä, sillä usein joudutaan testaamaan, onko annetussa listassa alkioita.

Listoja voidaan luoda myös list()-funktiolla.

Listoja voidaan luonnollisesti sijoittaa muuttujiin myöhempää käyttöä varten:

>>> vocabulary = ["ameliorate", "castigate", "defenestrate"]
>>> numbers = [17, 123]
>>> empty = []
>>> print vocabulary, numbers, empty
['ameliorate', 'castigate', 'defenestrate'] [17, 123] []

Alkioihin viittaaminen

Listan alkioihin viitataan aivan samoin kuin merkkijonojen kirjaimiin, käyttämällä indeksiä.

>>> print numbers[0]
17

Indeksien numerointi ja viipalointi toimivat listoilla aivan samoin kuin merkkijonoilla. Indeksinä voidaan käyttää mitä tahansa kokonaisluvuksi evaluoituvaa lauseketta.

>>> numbers[9-8]
5
>>> numbers[1.0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: list indices must be integers

Listaa voidaan käydä läpi indeksien avulla esimerkiksi näin:

horsemen = ["war", "famine", "pestilence", "death"]
i = 0
while i < 4:
    print horsemen[i]
    i += 1

Myös listojen pituuden voi selvittää funktiolla len()

>>> len(horsemen)
4

Huomattavaa on, että kuten edellä todettiin, listan sisällä olevaa listaa kohdellaan ulomman listan kannalta yhtenä alkiona, eli esimerkiksi listan [1, ‘a’, [1,2,3], ‘b’] pituus on 4.

Listan jäsenyys

Alkion kuulumista listaan voidaan testata in-operaattorilla

>>> 'death' in horsemen
True
>>> 'kuolema' in horsemen
False

Listaan kuulumattomuutta voidaan testata myös sanaa not yhdessä operaattorin in kanssa.

>>> 'kuolema' not in horsemen
True

Listaoperaatioita

Myös listoja voidaan liittää peräkkäin yhteen + -operaattorilla.

>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> c = a + b
>>> print c
[1, 2, 3, 4, 5, 6]

Vastaavasti kertolaskuoperaattori * liittää annetun kokonaisluvun mukaisen määrän samoja listoja peräkkäin

>>> [0] * 4
[0, 0, 0, 0]
>>> [1, 2, 3] * 3
[1, 2, 3, 1, 2, 3, 1, 2, 3]

Viipalointi

Viipalointi toimii listoille samoin kuin merkkijonoille

>>> a_list = ['a', 'b', 'c', 'd', 'e', 'f']
>>> a_list[1:3]
['b', 'c']
>>> a_list[:4]
['a', 'b', 'c', 'd']
>>> a_list[3:]
['d', 'e', 'f']
>>> a_list[:]
['a', 'b', 'c', 'd', 'e', 'f']

range()-funktio

Usein tarvittavia tasavälisiä lukujonoja on helppo luoda listoina range()-funktiolla. Yhdellä kokonaislukuargumentilla kutsuttuna range() tuottaa kokonaislukujonon, joka alkaa luvusta 0 ja jatkuu päättyäkseen juuri ennen argumenttina annettua lukua.

>>> range(10)
[0,1,2,3,4,5,6,7,8,9]

Kahdella kokonaislukuargumentilla kutsuttuna tuloksena saatava kokonaislukujono alkaa ensimmäisenä argumenttina annetusta luvusta ja päättyy juuri ennen toisena argumenttina annettua lukua.

>>> range(4,10)
[4,5,6,7,8,9]

Huomattavaa on, että kutsulla range(m,n) saadun listan pituus on n-m.

Jos range()-funktiolle annetaan myös kolmas argumentti, tämä tarkoittaa tuotettavan jonon alkioiden välisen askeleen pituutta.

>>> range(1,10,2)
[1,3,5,7,9]
>>> range(1,10,3)
[1,4,7]

Askeleen pituudeksi voidaan antaa myös negatiivinen luku, jolloin saadaan laskeva lukujono. Tällöin täytyy huomata, että aloitusluvun täytyy olla suurempi kuin lopetusluvun.

>>> range(20,7,-5)
[20,15,10]

Jos aloitus- ja lopetusluvut ovat väärin päin, on tuloksena tyhjä lista. Tämä siksi, että listan luonti lopetetaan ennen kuin saavutaan lopetuslukuun saakka, eli siis ennen kuin ensimmäistäkään lukua on lisätty listaan.

>>> range(2,9,-4)
[]
>>> range(9,2)
[]

Listat ovat muutettavia

Toisin kuin merkkijonot, ovat listat muutettavia. Listasta voidaan siis vaihtaa alkioita, poistaa alkioita ja siihen voidaan lisätä alkioita. Listan alkion muuttaminen tapahtuu yksinkertaisesti viittaamalla listan paikkaan, johon halutaan uusi alkio

>>> fruit = ['omppu','mandariini','bansku']
>>> fruit[0] = 'omena'
>>> fruit[-1] = 'banaani'
>>> print fruit
['omena','mandariini','banaani']

Viipalointimerkintää käyttämällä voidaan muokata listasta myös useampia alkioita kerralla

>>> fruit[1:2] = ['appelsiini','mansikka']
>>> print fruit
['omena', 'appelsiini', 'mansikka', 'banaani']

Tässä viipale fruit[1:2], eli ‘mandariini’ korvattiin listan [‘appelsiini’,‘mansikka’] alkioilla. Listasta voidaan myös poistaa alkioita korvaamalla viipale tyhjällä listalla.

>>> fruit[2:3] = []
>>> print fruit
['omena', 'appelsiini', 'banaani']

Alkioiden lisääminen onnistuu lisäämällä lista tyhjän viipaleen paikalle.

>>> fruit[2:2] = ['mandariini','mansikka']
>>> print fruit
['omena', 'appelsiini', 'mandariini', 'mansikka', 'banaani']

Lisää listoista kirjan kappaleessa 9.