Ohjelmoinnin peruskurssi Y1 CSE-A1111 30.9.2015 CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 1 / 27
Mahdollisuus antaa luentopalautetta Goblinissa vasemmassa reunassa olevassa valikossa on valinta Luentopalaute. Tätä kautta on mahdollisuus antaa nimettömänä palautetta luennosta. Jos jokin asia on jäänyt palautteen perusteella epäselväksi, palataan siihen mahdollisuuksien mukaan seuraavalla luennolla. CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 2 / 27
Oppimistavoitteet: tämän luennon jälkeen Osaat käsitellä useita yhteenkuuluvia arvoja yhden muuttujan kautta käyttämällä hyväksi listoja. Tiedät, miten listoja voidaan käyttää funktioiden parametreina ja paluuarvoina. Osaat kirjoittaa funktioita, jotka hakevat listasta esimerkiksi halutun arvon, jonkin ehdon täyttävien alkioiden lukumäärän tai parhaimman alkion (jossain mielessä). Tiedät, miten järjestyksessä olevasta listasta voi hakea haluttua arvoa tehokkaasti binäärihaulla. CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 3 / 27
Kertausta: listat Tyhjä uusi lista luodaan kirjoittamalla esimerkiksi lampotilat = [] ja nollia sisältävä lista esim tulokset = [0] * 15 Listan loppuun voi lisätä uuden arvon kirjoittamalla lampotilat.append(arvo) Jos listassa on jo vähintään i+1 alkiota, voi indeksille i sijoittaa uuden arvon kirjoittamalla lampotilat[i] = arvo Tällöin indeksillä i ollut vanha arvo häviää. Indeksit ovat kokonaislukuja ja listan ensimmäisen alkion indeksi on aina 0. Listan yksittäistä alkiota voi käyttää esim. seuraavasti print("5. lampotila", lampotilat[4]) summa = summa + lampotilat[4] CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 4 / 27
Kertausta: listan läpikäynti While-käskyn avulla: summa = 0 i = 0 while i < LKM: summa += lampotilat[i] i += 1 For-käskyn avulla summa = 0.0 for astemaara in lampotilat: summa += astemaara Muuttuja astemaara saa arvokseen vuorotellen jokaisen listan alkion. CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 5 / 27
Luentopalautteen kysymys: milloin while, milloin for listan läpikäyntiin? Jos toistokäskyssä ei tehdä muutoksia listan alkiohin, voi käyttää kumpaa hyvänsä. Jos toistokäskyn halutaan muuttavan listan alkioita, ei for-käskyä voida käyttää edellisen kalvon tapaan. Sen sijaan while-käsky toimii ilman ongelmia, esimerkiksi: i = 0 while i < len(hinnat): hinnat[i] = hinnat[i] * 1.24 i += 1 Myös for-käskyn käyttäminen on tällaisessa tapauksessa mahdollista, mutta silloin pitää käydä läpi listan indeksejä (yleensä range-funktion avulla), ei listan alkioita edellisen kalvon tapaan: for i in range(len(hinnat)): hinnat[i] = hinnat[i] * 1.24 CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 6 / 27
Esimerkki: hintalista Seuraavassa esimerkkiohjelmassa luetaan ensin kirjojen hintoja ja niiden alennusprosentti (sama kaikille kirjoille). Sen jälkeen tulostetaan uudelleen kirjojen alkuperäiset ja alennetut hinnat. Kirjojen lukumäärä pyydetään käyttäjältä. Kiinnitä huomiota erityisesti seuraaviin asioihin: Listan indeksien läpikäynti for-käskyn, range-funktion ja listan pituuden avulla. Tulostuksen muotoilun käyttäminen input-käskyssä. CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 7 / 27
def main(): lkm = int(input("anna kirjojen lukumaara: ")) hinnat = [0] * lkm alennus = float(input("anna alennus (%): ")) main() for i in range(lkm): hinnat[i] = float(input("kirjan {:d} hinta ".format( i + 1))) print("kirja alkuperainen alennettu hinta") for i in range(lkm): alennettu = (100 - alennus) / 100.0 * hinnat[i] print("{:4d}. {:8.2f} {:12.2f}".format( i + 1, hinnat[i], alennettu)) CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 8 / 27
Lista parametrina ja funktion palauttamana arvona Viime luennolla esitettyä lämpötiloja käsittelevää ohjelmaa voi selkiyttää jakamalla sen useampaan funktioon. Tällöin kuitenkin tiedon käsiteltävistä lämpötiloista pitää siirtyä eri funktioiden välillä. Tähän voidaan käyttää parametreja ja funktion paluuarvoa. Funktio voi palauttaa arvonaan listan ja funktiolle voidaan antaa parametrina lista. Jos funktio tekee muutoksia parametrina saadun listan sisältöön, näkyvät muutokset myös silloin, kun samaa listaa käytetään funktion ulkopuolella. CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 9 / 27
Esimerkki: listan palauttava funktio def kysy_lampotilat(): LKM = 30 lampotilat = [0.0] * LKM i = 0 print("anna", LKM, "lampotilaa") while i < LKM: lampo = float(input("seuraava lampotila: ")) lampotilat[i] = lampo i += 1 return lampotilat CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 10 / 27
Esimerkki: lista funktion parametrina def tulosta_lampotilat(lammot): print("annetut lampotilat") for arvo in lammot: print(arvo) def laske_keskiarvo(lampotilalista): summa = 0.0 for lampotila in lampotilalista: summa += lampotila lukumaara = len(lampotilalista) if lukumaara > 0: keskiarvo = summa / lukumaara else: keskiarvo = 0.0 return keskiarvo CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 11 / 27
Esimerkki: pääohjelma def main(): lampolista = kysy_lampotilat() tulosta_lampotilat(lampolista) k_arvo = laske_keskiarvo(lampolista) print("lampotilojen keskiarvo on {:.2f}".format(k_arvo)) main() CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 12 / 27
Ehdon tarkistus listan läpikäynnissä Hyvin usein halutaan etsiä listasta kaikki jonkin ehdon täyttävät arvot tai niiden lukumäärä. Esimerkiksi lämpötilalistasta halutaan annetun rajan ylittävien tai yhtäsuurten lämpötilojen lukumäärä. Kirjoitetaan toistokäsky, joka käy kaikki listan alkiot läpi. Toistokäskyn sisälle kirjoitetaan if-käsky, joka tarkistaa, onko haluttu ehto käsiteltävän alkion kohdalla tosi. Jos on, kasvatetaan löydettyjen alkioiden lukumäärää. Kun koko lista on käyty läpi, palautetaan löydettyjen alkioiden lukumäärä. Huomaa, että palautuskäsky pitää olla toistokäskyn ulkopuolella. CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 13 / 27
Rajan ylittävät lämpötilat, koodi def montako_yli_rajan(lampotilojen_lista, raja): ylittavien_maara = 0 for asteet in lampotilojen_lista: if asteet >= raja: ylittavien_maara += 1 return ylittavien_maara CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 14 / 27
Välitehtävä Seuraavan funktion on tarkoitus tarkistaa, ovatko kaikki parametrina annetun listan alkiot suurempia kuin toisena parametrina annettu luku. Miksi funktio ei toimi oikein? Miten sen voisi korjata? def kaikki_yli_rajan(lista, raja): for alkio in lista: if alkio > raja: return True else: return False CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 15 / 27
Halutuimman arvon etsiminen listasta Usein toistuva ongelma on myös löytää listasta halutuin arvo, esimerkiksi suurin lämpötila. Käytetään apumuuttujaa, johon tallennetaan tähän asti löydetty paras arvo. Aluksi apumuuttujan arvoksi alustetaan joko mahdollisimman huono arvo tai listan ensimmäisen alkion arvo. Käydään listan alkiot läpi toistokäskyssä. Jos tällä kierroksella tarkasteltava alkio on parempi kuin apumuuttujan arvo, vaihdetaan sen arvo apumuuttujan arvoksi. On myös jotenkin käsiteltävä se tilanne, että lista on tyhjä. Seuraavan kalvon esimerkkiohjelma etsii listasta suurimman lämpötilan. (Tähän voisi käyttää myös Python valmista funktiota max, mutta seuraavan kalvon periaatetta voi käyttää myös muun kuin maksimin etsimiseen.) CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 16 / 27
Maksimilämpötilan etsiminen, koodi def etsi_maksimi(lampotilalista): if len(lampotilalista) == 0: return None else: maksimi = lampotilalista[0] for lampotila in lampotilalista: if lampotila > maksimi: maksimi = lampotila return maksimi CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 17 / 27
Haku listasta: peräkkäishaku Usein toistuva ongelma: on tutkittava, löytyykö jokin arvo listasta ja jos löytyy, niin miltä indeksiltä. Jos luvut on tallennettu listaan mielivaltaisessa järjestyksessä, käytetään peräkkäishakua: käydään lista järjestyksessä läpi ja verrataan jokaista alkiota etsittävään arvoon. Läpikäyntiä jatketaan, kunnes haluttu arvo on löytynyt tai lista on käyty loppuun. Seuraavassa esimerkissä etsitään pistelistasta haluttu arvo. Mukana on myös funktio, joka ensin lukee pisteet listaan. Jos haluttu arvo esiintyy listassa monta kertaa, palautetaan niistä vain ensimmäisen indeksi. CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 18 / 27
Peräkkäishaku: koodi def lue_pisteet(): lkm = int(input("monenko pisteet haluat antaa? ")) pistelista = [0] * lkm i = 0 while i < len(pistelista): pistelista[i] = int(input("seuraavat pisteet: ")) i += 1 return pistelista def hae_pisteet(lista, arvo): for i in range(len(lista)): if lista[i] == arvo: return i return -1 CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 19 / 27
Peräkkäishaku, koodi jatkuu def main(): pisteet = lue_pisteet() haettava_arvo = int(input("mita arvoa etsitaan? ")) paikka = hae_pisteet(pisteet, haettava_arvo) if paikka == -1: print("haettavaa arvoa ei loytynyt pistelistasta") else: print("haettava arvo on listassa indeksilla", paikka) main() CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 20 / 27
Kaikkien arvojen haku Jos listasta halutaan hakea kaikki halutun arvon esiintymät, voidaan niiden indeksit kerätä listaan ja palauttaa ko. lista. Toinen vaihtoehto on kirjoittaa haun tekevä funktio niin, että se ei aloita listan alusta, vaan parametrina annetusta indeksistä. Funktiota kutsutaan monta kertaa niin, että seuraavalla kutsukerralla aloitusindeksi on aina edellisellä kerralla löydettyä indeksiä yhden suurempi. CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 21 / 27
Kaikkien esiintymien haku, koodi def hae_pisteet_kaikki(lista, arvo): tuloslista = [] for i in range(len(lista)): if lista[i] == arvo: tuloslista.append(i) return tuloslista CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 22 / 27
Operaattori in Pythonissa on valmis operaattori in, jonka avulla voidaan tutkia, onko haettava arvo annetussa listassa: if haettava_arvo in pisteet: print("haettava arvo on pistelistassa") else: print("haettava arvo ei ole pistelistassa") Tai vaihtoehtoisesti: if haettava_arvo not in pisteet: print("haettava arvo ei ole pistelistassa") else: print("haettava arvo on pistelistassa") Operaattorin in käyttäminen ei ole kuitenkaan olennaisesti sen tehokkaampaa kuin listan läpikäyminen omalla funktiolla. CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 23 / 27
Metodi index Pythonissa on myös valmis metodi index, jonka avulla voidaan hakea halutun alkion indeksi listasta. Metodi on kuin funktio, mutta sitä kutsutaan vähän eri tavalla: listamuuttuja.metodi(parametrit) Esimerkki metodin index kutsumisesta: paikka = pisteet.index(haettava_arvo) Tämä johtaa kuitenkin ohjelman kaatumiseen, jos haettavaa arvoa ei ole pistelistassa. Sen vuoksi kannattaa ensin tarkistaa, että arvo on listassa: if haettava_arvo not in pisteet: print("haettava arvo ei ole pistelistassa") else: paikka = pisteet.index(haettava_arvo) print("haettava arvo on listassa indeksilla", paikka) CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 24 / 27
Binäärihaku Jos tiedetään, että listassa olevat alkiot ovat suuruusjärjestyksessä, binäärihaku on selvästi tehokkaampi kuin peräkkäishaku. Periaate: 1. Valitaan koko lista hakualueeksi. 2. Lasketaan hakualueen keskimmäisen alkion indeksi. 3. Verrataan keskimmäistä alkiota haettavaan alkioon. Jos ne ovat yhtäsuuret, haettava alkio on löytynyt, joten lopetetaan. 4. Jos haettava alkio on pienempi, jatketaan kohdasta 2 niin, että hakualueena on alkuperäisen hakualueen alkupuolisko. 5. Jos haettava alkio on suurempi, jatketaan kohdasta 2 niin, että hakualueena on alkuperäisen hakualueen loppupuolisko. CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 25 / 27
Esimerkki binäärihausta Haetaan luku 14 annetusta listasta 2 7 8 12 14 17 24 29 0 1 2 3 4 5 6 7 30 32 39 50 54 58 61 8 9 10 11 12 13 14 14 < 29 CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 26 / 27
Esimerkki binäärihausta Haetaan luku 14 annetusta listasta 2 7 8 12 14 17 24 29 0 1 2 3 4 5 6 7 30 32 39 50 54 58 61 8 9 10 11 12 13 14 14 < 29 2 7 8 12 0 1 2 3 14 17 24 4 5 6 14 > 12 CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 26 / 27
Esimerkki binäärihausta Haetaan luku 14 annetusta listasta 2 7 8 12 14 17 24 29 0 1 2 3 4 5 6 7 30 32 39 50 54 58 61 8 9 10 11 12 13 14 14 < 29 2 7 8 12 0 1 2 3 14 17 24 4 5 6 14 > 12 14 4 17 24 5 6 14 < 17 CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 26 / 27
Esimerkki binäärihausta Haetaan luku 14 annetusta listasta 2 7 8 12 14 17 24 29 0 1 2 3 4 5 6 7 30 32 39 50 54 58 61 8 9 10 11 12 13 14 14 < 29 2 7 8 12 0 1 2 3 14 17 24 4 5 6 14 > 12 14 4 17 24 5 6 14 < 17 14 4 14 == 14 CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 26 / 27
Binäärihaku, koodi def binaarihaku(lista, arvo): ala = 0 yla = len(lista) - 1 while ala <= yla: keski = (ala + yla) // 2 if lista[keski] == arvo: return keski elif lista[keski] < arvo: ala = keski + 1 else: yla = keski - 1 return -1 CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 27 / 27