Kirjautuminen

Haku

Tehtävät

Opasarkisto: Python 2 -ohjelmointi: Osa 10 - Tietorakenteet

  1. Osa 1 - Ensimmäinen ohjelma
  2. Osa 2 - Tiedon käsittely
  3. Osa 3 - Ehtorakenteet
  4. Osa 4 - Toistorakenteet
  5. Osa 5 - Listojen käsittely
  6. Osa 6 - Merkkijonot
  7. Osa 7 - Omat funktiot
  8. Osa 8 - Tiedostot ja virheet
  9. Osa 9 - Standardikirjasto
  10. Osa 10 - Tietorakenteet
  11. Osa 11 - Alkeita edemmäs
  12. Osa 12 - Yhteenveto
  13. Liite 1 - Asennus ja käyttö
  14. Liite 2 - Python ja ääkköset

Kirjoittaja: Antti Laaksonen (2009).

⚠ Huomio! Tämä opas on vanhentunut. Oppaan sisältöön ei voi enää luottaa. Opas on säilytetty vain sen historiallisen arvon vuoksi. ⚠


Tähän mennessä listan alkiot ovat olleet vain lukuja ja merkkijonoja, mutta listan alkiot voivat olla myös listoja. Tämän ansiosta listan alkiot voivat sisältää monta erillistä tietoa tai lista voi esimerkiksi esittää kaksiulotteista ruudukkoa. Edelleen listan sisällä voi olla monta sisäkkäistä tasoa listoja, mikä mahdollistaa monimutkaisten tietorakenteiden toteutuksen.

Tämä opas esittelee sisäkkäisten listojen käyttöä esimerkkien avulla. Lisäksi oppaan lopussa tulee tutuksi Python-kielen tietorakenne sanakirja, josta voi hakea kätevästi tietoa hakuavaimen avulla.

Lista listassa

Seuraavassa ohjelmassa listan sisällä on kolme alilistaa:

# -*- coding: latin-1 -*-

listat = [[1, 2, 3, 4],
          [5, 6, 7, 8, 9, 10],
          [11, 12]]

print "Listoja yhteensä:", len(listat)
print "1. lista:", listat[0]
print "2. lista:", listat[1]
print "3. lista:", listat[2]
print "1. listan 2. luku:", listat[0][1]
print "2. listan 4. luku:", listat[1][3]
print "3. listan 1. luku:", listat[2][0]

print "Kaikki luvut:"
for lista in listat:
    for luku in lista:
        print luku,
    print

Ohjelman tulostus on seuraava:

Listoja yhteensä: 3
1. lista: [1, 2, 3, 4]
2. lista: [5, 6, 7, 8, 9, 10]
3. lista: [11, 12]
1. listan 2. luku: 2
2. listan 4. luku: 8
3. listan 1. luku: 11
Kaikki luvut:
1 2 3 4
5 6 7 8 9 10
11 12

Listan listat alkiot ovat alilistoja, joiden alkiot ovat lukuja. Merkintä listat[a] viittaa tiettyyn alilistaan, ja merkintä listat[a][b] viittaa tietyn alilistan tiettyyn lukuun. Edelleen alilistojen sisällä voisi olla alialilistoja jne., jolloin hakasulkuja ja sisäkkäisiä for-silmukoita tulisi lisää.

Esimerkki: Tuloslista

Seuraava ohjelma tulostaa pelin tuloslistan:

# -*- coding: latin-1 -*-

lista = [["Uolevi", 100],
         ["Henrikki", 80],
         ["Antti", 30],
         ["Nimetön", 0],
         ["Nimetön", 0]]

for tulos in lista:
    print "Nimi:", tulos[0]
    print "Pisteet:", tulos[1]

Ohjelman tulostus on seuraava:

Nimi: Uolevi
Pisteet: 100
Nimi: Henrikki
Pisteet: 80
Nimi: Antti
Pisteet: 30
Nimi: Nimetön
Pisteet: 0
Nimi: Nimetön
Pisteet: 0

Tässä listan alkiot muodostuvat kahdesta osasta: ensin tulee pelaajan nimi, sitten hänen pistemääränsä.

Esimerkki: Labyrintti

Seuraava ohjelma piirtää labyrintin listan perusteella:

# -*- coding: latin-1 -*-
kartta = [[1, 1, 1, 1, 1, 1],
          [1, 2, 1, 1, 0, 0],
          [1, 0, 0, 0, 0, 1],
          [1, 0, 1, 1, 0, 1],
          [1, 0, 0, 0, 0, 1],
          [1, 1, 1, 1, 1, 1]]
merkit = " #@"
for rivi in kartta:
    for ruutu in rivi:
        print merkit[ruutu],
    print

Ohjelman tulostus on seuraava:

# # # # # #
# @ # #
#         #
#   # #   #
#         #
# # # # # #

Listassa kartta kerrotaan jokaisesta labyrintin ruudusta, onko se lattiaa (0), seinää (1) vai onko siinä pelaaja (2). Merkkijonossa merkit lukee, mitkä merkit vastaavat erilaisia labyrintin ruutuja.

Seuraavassa ohjelmassa pelaaja voi liikkua labyrintissa:

# -*- coding: latin-1 -*-
kartta = [[1, 1, 1, 1, 1, 1],
          [1, 2, 1, 1, 0, 0],
          [1, 0, 0, 0, 0, 1],
          [1, 0, 1, 1, 0, 1],
          [1, 0, 0, 0, 0, 1],
          [1, 1, 1, 1, 1, 1]]
omay = 1
omax = 1
merkit = " #@"
while True:
    for rivi in kartta:
        for ruutu in rivi:
            print merkit[ruutu],
        print
    if omay == 1 and omax == 5:
        print "Pääsit maaliin!"
        break
    suunta = raw_input("Suunta (y/a/v/o): ")
    uusix = omax
    uusiy = omay
    if suunta == "y":
        uusiy = omay - 1
    if suunta == "a":
        uusiy = omay + 1
    if suunta == "v":
        uusix = omax - 1
    if suunta == "o":
        uusix = omax + 1
    if kartta[uusiy][uusix] == 0:
        kartta[omay][omax] = 0
        kartta[uusiy][uusix] = 2
        omay = uusiy
        omax = uusix

Ohjelman tulostus voi olla seuraava:

# # # # # #
# @ # #
#         #
#   # #   #
#         #
# # # # # #
Suunta (y/a/v/o): a
# # # # # #
#   # #
# @       #
#   # #   #
#         #
# # # # # #
Suunta (y/a/v/o): o
# # # # # #
#   # #
#   @     #
#   # #   #
#         #
# # # # # #
Suunta (y/a/v/o): o
# # # # # #
#   # #
#     @   #
#   # #   #
#         #
# # # # # #
Suunta (y/a/v/o): o
# # # # # #
#   # #
#       @ #
#   # #   #
#         #
# # # # # #
Suunta (y/a/v/o): y
# # # # # #
#   # # @
#         #
#   # #   #
#         #
# # # # # #
Suunta (y/a/v/o): o
# # # # # #
#   # #   @
#         #
#   # #   #
#         #
# # # # # #
Pääsit maaliin!

Muuttujissa omay ja omax on pelaajan sijainti labyrintissa. Kun pelaaja ilmoittaa liikesuunnan, muuttujiin uusiy ja uusix tulee pelaajan uusi sijainti. Jos sijainti kelpaa (pelaaja ei mene seinän päälle), muuttujat kartta, omay ja omax päivittyvät.

Sanakirja

Sanakirja on Python-kielen tietorakenne, josta voi hakea kätevästi tietoa hakuavaimen avulla. Sanakirja muistuttaa listaa, mutta siinä alkioiden tunnukset saa valita itse järjestyksessä olevien kokonaislukujen sijaan.

Seuraava ohjelma kääntää sanan suomesta hollanniksi:

# -*- coding: latin-1 -*-
sanat = {"talo":"huis",
         "metsä":"bos",
         "katu":"straat",
         "auto":"auto",
         "puu":"boom"}
sana = raw_input("Anna sana: ")
if sana in sanat:
    print "Hollanniksi:", sanat[sana]
else:
    print "Tuntematon sana!"

Ohjelman tulostus voi olla seuraava:

Anna sana: katu
Hollanniksi: straat

Sanakirja merkitään aaltosulkujen sisään, ja hakuavaimia ja arvoja erottavat kaksoispisteet. Tässä sanakirjan hakuavaimet ovat suomen kielen sanoja, ja niitä vastaavat hollannin kielen sanat. Esimerkiksi sanat["katu"] on "straat" ja sanat["puu"] on "boom".

Esimerkki: Sanalaskuri

Seuraava ohjelma laskee, kuinka monta kertaa käyttäjä kirjoittaa eri sanoja:

# -*- coding: latin-1 -*-

sanat = {}

while True:
    sana = raw_input("Anna sana: ")
    if sana == "":
        break
    if sana in sanat:
        sanat[sana] += 1
    else:
        sanat[sana] = 1

for sana in sanat:
    print "Kirjoitit", sanat[sana], "kertaa sanan", sana

Ohjelman tulostus voi olla seuraava:

Anna sana: banaani
Anna sana: apina
Anna sana: banaani
Anna sana: cembalo
Anna sana: apina
Anna sana: apina
Anna sana:
Kirjoitit 2 kertaa sanan banaani
Kirjoitit 1 kertaa sanan cembalo
Kirjoitit 3 kertaa sanan apina

Tässä sanakirjan hakuavaimet ovat käyttäjän kirjoittamat sanat. Jos käyttäjä kirjoittaa uuden sanan, ohjelma lisää sanakirjaan sen arvoksi 1. Jos käyttäjä kirjoittaa saman sanan uudestaan, ohjelma kasvattaa sen arvoa sanakirjassa.

Esimerkki: Anagrammit

Seuraava ohjelma etsii suomen kielen sanalistasta anagrammeja eli sanoja, jotka sisältävät yhtä monta jokaista kirjainta. Ohjelma tulostaa kaikki sanaryhmät, joissa sanat ovat toistensa anagrammeja ja sanoja on ainakin viisi.

Suomen kielen sanalista esiintyi aiemmin oppaassa 8.

# -*- coding: latin-1 -*-

tiedosto = open("kotus_sanat.txt", "r")
sanat = tiedosto.readlines()
tiedosto.close()

anagrammit = {}

def jarjesta(sana):
    merkit = list(sana)
    merkit.sort()
    return "".join(merkit)

for sana in sanat:
    sana = sana.strip()
    avain = jarjesta(sana)
    if avain not in anagrammit:
        anagrammit[avain] = [sana]
    else:
        anagrammit[avain].append(sana)

for avain in anagrammit:
    if len(anagrammit[avain]) >= 5:
        for sana in anagrammit[avain]:
            print sana,
        print

Ohjelman tulostus on seuraava:

anturi nutria rutina tunari turina
alistuva luistava ulvaista valistua vilustaa
altis lasti lista litsa silat silta tilsa
altistaa laastita lasittaa latistaa salaatti
keriä kierä kireä reikä räike
aristus irstaus rasitus surista tussari
altistua istualta lasittua latistua sulittaa tulistaa
ravet tarve terva varte verta
paristo pastori pirstoa porista ropista
aluksi kilaus liukas liuska luiska saluki sulkia
karsia kasari raikas raiska raksia raskia
kiulu kuilu liuku luiku ukuli
otsa sato sota taos taso

Ohjelma tallentaa sanat sanakirjaan listoihin, joissa kaikki sanat ovat toistensa anagrammeja. Sanasta muodostettava hakuavain sisältää sanan kirjaimet aakkosjärjestyksessä, jolloin kahdella sanalla on sama avain, jos ne ovat anagrammeja, ja kahdella sanalla on eri avain, jos ne eivät ole anagrammeja.

Esimerkiksi sanan "anturi" hakuavain on "ainrtu" ja sanakirjan kohdassa anagrammit["ainrtu"] on lopuksi lista ["anturi", "nutria", "rutina", "tunari", "turina"].

Funktiossa jarjesta funktio list muuttaa ensin merkkijonon listaksi, jonka alkiot ovat merkkijonon kirjaimet. Listan järjestämisen jälkeen metodi join muuttaa listan takaisin merkkijonoksi lisäämällä listan jokaisen alkion väliin tyhjän merkkijonon.


Kommentit

Jormapythoni [23.08.2014 23:08:39]

#

Huippu ohjelma, nopeasti tajuaa ohjelmoinnin juonen..
Tein tuommosen muunnelman labyrintistä mutta en saanut tuota breik:kiä jostain syystä toimimaan (while True ei `katkea`)

# -*- coding: latin-1 -*-
kartta = [[1, 1, 1, 1, 1, 1, 1, 1, 1],
          [1, 2, 1, 0, 0, 0, 0, 1, 1],
          [1, 0, 0, 0, 1, 1, 0, 0, 1],
          [1, 1, 1, 1, 1, 1, 1, 0, 1],
          [1, 0, 0, 0, 0, 0, 0, 0, 1],
          [1, 0, 1, 1, 1, 1, 0, 1, 1],
          [1, 1, 1, 0, 0, 1, 0, 0, 1],
          [0, 0, 1, 1, 0, 0, 1, 0, 1],
          [1, 0, 1, 1, 1, 0, 1, 0, 1],
          [1, 0, 0, 0, 1, 0, 0, 0, 1],
          [1, 1, 1, 0, 0, 0, 1, 1, 1],
          [1, 1, 1, 1, 1, 1, 1, 1, 1]]
pisteet = 0
omay = 1
omax = 1
merkit = " XO"
while True:
    for rivi in kartta:
        for ruutu in rivi:
            print merkit[ruutu],
        print
    if omay == 7 and omax == 0:
        pisteet +=10
        print "Pääsit maaliin, Saat 10 lisäpistettä!"
    if pisteet == 12:
        print "Löysit myös kummankin kaverisi! Pisteet: ", pisteet
    if pisteet == 11:
        print "Löysit yhden kaverinkin matkanvarrelta! Pisteet: ", pisteet
    if pisteet == 10:
        print "Et löytänyt yhtään kaveria.. Pisteet: ", pisteet
        break

    if omay == 5 and omax == 1:
        print "Löysit kaverin! +1 piste"
        pisteet +=1
    if omay == 6 and omax == 3:
        print "Löysit kaverin! +1 piste"
        pisteet +=1


    suunta = raw_input("Suunta (y/a/v/o): ")
    uusix = omax
    uusiy = omay
    if suunta == "y":
        uusiy = omay - 1
    if suunta == "a":
        uusiy = omay + 1
    if suunta == "v":
        uusix = omax - 1
    if suunta == "o":
        uusix = omax + 1
    if kartta[uusiy][uusix] == 0:
        kartta[omay][omax] = 0
        kartta[uusiy][uusix] = 2
        omay = uusiy
        omax = uusix

Mirox [07.10.2014 05:18:34]

#

Jormapythoni kirjoitti:

Huippu ohjelma, nopeasti tajuaa ohjelmoinnin juonen..
Tein tuommosen muunnelman labyrintistä mutta en saanut tuota breik:kiä jostain syystä toimimaan (while True ei `katkea`)

Itse sain ton sun labyrintin toimimaan lisäämällä

if pisteet > 2:
    break

Toivottavasti auttoi!

poksuuu [31.10.2014 16:08:55]

#

Jormapythoni kirjoitti:

Huippu ohjelma, nopeasti tajuaa ohjelmoinnin juonen..
Tein tuommosen muunnelman labyrintistä mutta en saanut tuota breik:kiä jostain syystä toimimaan (while True ei `katkea`)

Hienon labyrintin väsäsit! Sain ainakin noin toimimaan, mutta huomasin samalla että saman henkilön voi poimia useamman kerran. En itse keksinyt miten sen saisi vielä korjattua.

# -*- coding: latin-1 -*-
kartta = [[1, 1, 1, 1, 1, 1, 1, 1, 1],
          [1, 2, 1, 0, 0, 0, 0, 1, 1],
          [1, 0, 0, 0, 1, 1, 0, 0, 1],
          [1, 1, 1, 1, 1, 1, 1, 0, 1],
          [1, 0, 0, 0, 0, 0, 0, 0, 1],
          [1, 0, 1, 1, 1, 1, 0, 1, 1],
          [1, 1, 1, 0, 0, 1, 0, 0, 1],
          [0, 0, 1, 1, 0, 0, 1, 0, 1],
          [1, 0, 1, 1, 1, 0, 1, 0, 1],
          [1, 0, 0, 0, 1, 0, 0, 0, 1],
          [1, 1, 1, 0, 0, 0, 1, 1, 1],
          [1, 1, 1, 1, 1, 1, 1, 1, 1]]
pisteet = 0
omay = 1
omax = 1
merkit = " XO"
while True:
    for rivi in kartta:
        for ruutu in rivi:
            print merkit[ruutu],
        print
    if omay == 7 and omax == 0:
        pisteet +=10
        print "Pääsit maaliin, Saat 10 lisäpistettä!"
        break
    if omay == 5 and omax == 1:
        print "Löysit kaverin! +1 piste"
        pisteet +=1
    if omay == 6 and omax == 3:
        print "Löysit kaverin! +1 piste"
        pisteet +=1

    suunta = raw_input("Suunta (y/a/v/o): ")
    uusix = omax
    uusiy = omay
    if suunta == "y":
        uusiy = omay - 1
    if suunta == "a":
        uusiy = omay + 1
    if suunta == "v":
        uusix = omax - 1
    if suunta == "o":
        uusix = omax + 1
    if kartta[uusiy][uusix] == 0:
        kartta[omay][omax] = 0
        kartta[uusiy][uusix] = 2
        omay = uusiy
        omax = uusix

if pisteet > 12:
    print "Nyt taisit huijata :)"
if pisteet == 12:
    print "Löysit myös kummankin kaverisi! Pisteet: ", pisteet
if pisteet == 11:
    print "Löysit yhden kaverinkin matkanvarrelta! Pisteet: ", pisteet
if pisteet == 10:
    print "Et löytänyt yhtään kaveria.. Pisteet: ", pisteet

lare290 [22.05.2015 17:22:43]

#

Tahdoin vain laittaa tähän tekemäni muunnelman labyrintistä, siellä on nyt myös ansa ja mörkö.

# -*- coding: latin-1 -*-
kartta = [[1, 1, 1, 1, 1, 1],
          [1, 2, 1, 1, 0, 0],
          [1, 0, 0, 0, 0, 1],
          [1, 0, 1, 1, 0, 1],
          [1, 0, 0, 3, 0, 1],
          [1, 1, 1, 1, 1, 1]]
omay = 1
omax = 1
morkoy = 4
morkox = 3
ansay = 3
ansax = 4
merkit = " #@ö"
while True:
    for rivi in kartta:
        for ruutu in rivi:
            print merkit[ruutu],
        print
    if omay == 1 and omax == 5:
        print "Pääsit maaliin!"
        break
    suunta = raw_input("Suunta (y/a/v/o): ")
    uusix = omax
    uusiy = omay
    if suunta == "y":
        uusiy = omay - 1
    if suunta == "a":
        uusiy = omay + 1
    if suunta == "v":
        uusix = omax - 1
    if suunta == "o":
        uusix = omax + 1
    if kartta[uusiy][uusix] == 0:
        kartta[omay][omax] = 0
        kartta[uusiy][uusix] = 2
        omay = uusiy
        omax = uusix
    if omay == ansay and omax == ansax:
        print "Astuit ansaan ja kuolit lol."
        break

    if omay == morkoy - 1 or omay == morkoy + 1 or omay == morkoy:
        if omax == morkox -1 or omax == morkox +1 or omax == morkox:
            print "Mörkö söi sut ja kuolit."
            break

Chiman [17.06.2015 11:35:20]

#

Huomasin että sanakirjan hyödyllinen items-metodi on jätetty esittelemättä tässä oppaassa. Sen avulla on helppo iteroida sanakirjan avain-arvo-pareja. Esim. Sanalaskuri-esimerkin kohta

for sana in sanat:
    print "Kirjoitit", sanat[sana], "kertaa sanan", sana

on items-metodin kanssa tällainen:

for sana, n in sanat.items():
    print "Kirjoitit", n, "kertaa sanan", sana

Vaihtoehtoisesti merkkijonoja voi koostaa %-operaattorilla näin:

for sana, n in sanat.items():
    print "Kirjoitit %d kertaa sanan %s" % (n, sana)

Uusin (Python 2.6 ja myöhemmät), selkein ja joustavin tapa on käyttää nimettyjä paikanosoittimia merkkijonon format-metodin kanssa:

for sana, n in sanat.items():
    print "Kirjoitit {n} kertaa sanan {s}".format(n=n, s=sana)

Lisätietoa format-metodin tarjoamista monipuolisista ominaisuuksista:
https://docs.python.org/2/library/string.html­#format-specification-mini-language

Kirjoita kommentti

Huomio! Kommentoi tässä ainoastaan tämän oppaan hyviä ja huonoja puolia. Älä kirjoita muita kysymyksiä tähän. Jos koodisi ei toimi tai tarvitset muuten vain apua ohjelmoinnissa, lähetä viesti keskusteluun.

Muista lukea kirjoitusohjeet.
Tietoa sivustosta