Programozás python nyelven
SMS
2007-05-18 - emelt szintű érettségi

Feladatleírás

Napjainkban a kommunikáció egy elterjedt formája az SMS-küldés. Az SMS-küldésre alkalmas telefonok prediktív szövegbevitellel segítik az üzenetek megírását. Ennek használatakor a szavakat úgy tudjuk beírni, hogy a telefon számbillentyűjén található betűknek megfelelő számokat kell beírnunk. A számok és betűk megfeleltetését az alábbi táblázat mutatja:
sms01
Ha meg szeretnénk jeleníteni az „ablak” szót, akkor a 22525 kódot kell beírnunk. A telefon a tárolt szótára alapján a kódhoz kikeresi a megfelelő szót. Ha több szóhoz is azonos kód tartozik, akkor a kódhoz tartozó összes szót felkínálja választásra. Egy ilyen szógyűjteményt talál a szavak.txt fájl-ban. A fájlról a következőket tudjuk:
  • Legfeljebb 600 szó található benne.
  • Minden szó külön sorban található.
  • A szavak hossza maximum 15 karakter.
  • A szavak mindegyike csak az angol ábécé kisbetűit tartalmazza.
  • Minden szó legfeljebb egyszer szerepel.
Írjon sms néven programot, ami a szógyűjtemény felhasználásával megoldja az alábbi feladatokat!

1. feladat
1. Kérjen be a felhasználótól egy betűt, és adja meg, hogy milyen kód (szám) tartozik hozzá! Az eredményt írassa a képernyőre!

Először egy kis elmélet:
Eldöntés és Kiválasztás tétele
A programozási tételek megkönnyítik a feladatok megoldását. Amennyiben egy probléma megoldása visszavezethető egy programozási tételre, akkor nincs más dolgod, mint alkalmazd. Ebben az esetben a kiválasztás tételének alkalmazása kézenfekvő, hiszen tudjuk, hogy egy halmazban ott van a keresett elem, csak azt nem tudjuk hányadik (melyik az). Tehát csak ki kell választani a megfelelőt a listából. A legegyszerűbb eset, ha csak azt kell eldönteni, hogy van-e benne számunkra megfelelő elem, ez az ELDÖNTÉS tétele:
Általános megfogalmazás:
Eldöntés: Adott egy N elemű sorozat és az azon értelmezhető T tulajdonság. Döntsd el van-e a sorozatnak T tulajdonságú eleme!
Kiválasztás: Adott egy N elemű sorozat és az azon értelmezhető T tulajdonság. Valamint azt is tudjuk, hogy a sorozatnak van legalább egy T tulajdonságú eleme. Határozd meg a T tulajdonságú elemének az indexét.

Eldöntés: A T sorozat tartalmaz-e T tulajdonságú elemet?
bemenet: T[] tömb
i = 0;
N = tömb hossza
Ciklus amig  i < N és T[i] nem T tulajdonságú
   i++
Ciklusvége
VAN = (i<N)
Ha azonban biztosan tudjuk, hogy a keresett elem benne van a listában, akkor már nem kell a végét figyelni, mert legrosszabb esetben az utolsó elem az amelyiket keresed.
Ez a Kiválasztás tétele.
Kiválasztás: A T sorozat tartalmaz T tulajdonságú elemet, mi a sorszáma?
bemenet: T[] tömb
i = 0;
N = tömb hossza
Ciklus amig  T[i] nem T tulajdonságú
   i++
Ciklusvége
kimenet: index = i
A feladat megoldása
Mindenek előtt a billentyűket tároljuk egy listában a következő módon. Az egyes billentyűkön látható betűket egy string-ben tárolom a billentyűket pedig egy listában.
bill=["abc", "def", "ghi", "jkl", "mno","pqrs","tuv", "wxyz"]
Most pedig válasszuk ki a billentyűk közül azt, amelyik a megadott betűt tartalmazza.
print("1. feladat")
beBill = input("Kérek egy betűt: ")
i=0
while bill[i].count(beBill) != 1:
    i += 1
print(i+2)
Természetesen, ha bolondbiztossá akarod tenni (ezt nem kéri az érettségi feladat), akkor a kiválasztás tétele helyett alkalmazd a keresés tételét, amely az eldöntés tétele egybegyúrva a kiválasztás tételével.

2. feladat
Kérjen be a felhasználótól egy szót, és határozza meg, hogy milyen számsorral lehet ezt a telefonba bevinni! Az eredményt írassa a képernyőre!
Itt már világosan látszik, hogy az előző feladat megoldását itt is felhasználhatom, tehát hatékony lenne, ha készítenék egy függvényt, amelyik egy megadott betű alapján visszatér a billentyű sorszámával.
def BetuSzama(betu):
    i=0
    while bill[i].count(beBill) != 1:
        i += 1
    return i+2
Az előző feladatot már nem kell módosítani, bár elegáns lenne. Viszont figyeld meg, hogy így milyen áttekinthető és egyszerű a 2. feladat megoldása.
print("2. feladat")
beSzo = input(("Kérek egy szót: ")
for betu in beSzo:
    print(betuSzama(betu),end=""))
print("")
A print() utasítás alapból sortöréssel záródik ("/n"), ha azt szeretnénk, hogy a következő kiírt adat ne új sorba kezdődjön, akkor küldjük el az end="" paramétert is.
Ebből világosan következik, hogy ha az end=";/n" karakter sorozatot küldöd paraméterként, akkor minden kiírás végén pontosvessző lesz és sortörés.

3. feladat
Olvassa be a szavak.txt fájlból a szavakat, és a továbbiakban azokkal dolgozzon! Ha nem tudja az állományból beolvasni az adatokat, akkor az állományban található „b” kezdőbetűs szavakat gépelje be a programba, és azokkal oldja meg a feladatokat!
Most már igen nagy rutinunk van állományból beolvasásban. Ez megint egy egyszerű lista feltöltése. Nézzük:
print("3. feladat")
szavak = []
with open("szavak.txt","r",encoding="utf-8") as szavakFile:
    for egySor in szavakFile:
        szavak.append(egySor.strip())
Mivel a szavak.txt minden szava külön sorban van ezért a sorzáró karaktert kell eltávolítani a beolvasáskor (strip()) és minden sort hozzáfűzni (append()) a szavak listához.
  
4. feladat
Határozza meg és írassa a képernyőre, hogy melyik a leghosszabb tárolt szó! Amennyiben több azonos hosszúságú van, elegendő csak az egyiket megjeleníteni. Adja meg ennek a szónak a hosszát is!
Ez egy maximum kiválasztás tétel. A lényeg, hogy amikor a probléma megoldásához kezdesz a lista első eleme a leghosszabb, Majd minden következő elemet összehasonlítasz az aktuális leghosszabbal, ha nagyobbat találsz, akkor az lesz a leghosszabb.
Általános megfogalmazás: Adott egy N elemű sorozat és a sorozat elemein értelmezhető T tulajdonság. Melyik a legnagyobb eleme a sorozatnak?
  
A T sorozatnak melyik a legnagyobb eleme?
bemenet: T[0..N-1] tömb (lista, sorozat)

maxIndex = 0 #Ez a sorozat első elemének indexe, jelenleg a legnagyobb elem a T[0]
i = 1; #Ez a sorozat második elemének indexe
N = lista hossza
Ciklus amíg  i < N 
   Ha T[i] > T[maxIndex] akkor maxIndex = i 
   #Ha az aktuális sorszámú elem nagyobb, mint az aktuális legnagyobb, akkor ez az új legnagyobb.
   i++
Ciklusvége
MAXIMUM = T[maxIndex]
Tisztán a tételt alkalmazva így néz ki:
print("4. feladat")
maxIndex = 0
i = 1
while i < len(szavak):
    if len(szavak[i]) > szavak[maxIndex]:
        maxIndex = i
    i += 1
print(szavak[maxIndex])
Ez egy másik megoldás:
print("4. feladat")
maxIndex = 0
for i in range(1, len(szavak)):
    if len(szavak[i]) > szavak[maxIndex]:
        maxIndex = i
print(szavak[maxIndex])
A for i in  range(1, len(szavak) egy számlálós ciklus, amelyben az i ciklusváltozó értéke a range(1, len(szavak)) függvény által meghatározott tartomány értékeit veszi fel. Ebben az esetben a kezdőérték 1, az utolsó érték a szavak lista hossza - 1. A harmadik megoldás pedig ez:
print("4. feladat")
max = szavak[0]
for egySzo in szavak:
    if len(egySzo) > len(max):
        max = egySzo
print(max)
Egy kis érdekesség, ez a Python nyelv lehetőségeit kihasználó megoldás:
print("4. feladat")
szoHosszak = list(map(len, szavak))
print(szavak[szoHosszak.index(max(szoHosszak)))
Magyarázat: A map() függvény első paramétere a len függvény, a második a szavak lista. A map() függvény a szavak lista minden elemén végrehajtja a len() függvényt és egy listába pakolja a list() függvény segítségével. Létrejött tehát egy a szavak hosszát tároló lista. (szoHosszak). A max() függvény megadja a legnagyobb értéket a szoHosszak litából. A szoHosszak.index() metódusa visszadja a legnagyobb érték indexét, amely pont a szavak lista leghosszabb szavának az indexe is egyben.
  
5. feladat
Határozza meg és írassa a képernyőre, hogy hány rövid szó található a fájlban! Rövid szónak tekintjük a legfeljebb 5 karakterből álló szavakat.
Ez egy megszámlálás tétel, amelyik arra hivatott, hogy egy adott sorozat megfelelő tulajdonságú elemeit megszámolja.
Általános megfogalmazás: Adott egy N elemű sorozat és sorozat elemein értelmezhető T tulajdonság. Számold meg, hogy a sorozatnak hány T tulajdonságú eleme van.
  
A T sorozatnak hány T tulajdonságú eleme van?
bemenet: T[0..N-1] tömb (lista, sorozat)

darab = 0 
i = 0; #Ez a ciklus változó, a sorozat 1. elemétöl kezdünk, aminek indexe 0
N = lista hossza
Ciklus amíg  i < N 
   Ha T[i] T tulajdonságú akkor
      darab ++ # Növeljük eggyel a darbszámot
   i++
Ciklusvége
Kimenet: darab
A sorozat vagy lista a szavak a T tulajdonság a szavak hossza (len(szavak[i])). A feladat, hogy azokat számoljuk meg, amelyek legfeljebb 5 betűből állnak len(szavak[i] >= 5). Ez megszámlálás tétel szó szerinti alkalmazása:
print("5. feladat")
darab = 0
i = 0
while i < len(szavak):
    if len(szavak[i]) <= 5:
        darab += 1
    i += 1
print(darab)
Ez a Pythonos változat:
print("5. feladat")
darab = 0
for egySzo in szavak:
    if len(egySzo) <= 5:
        darab += 1
print(darab)
6. feladat
Írassa a kodok.txt állományba a szavak.txt fájlban található szavaknak megfelelő számkódokat! Minden szónak feleljen meg egy számkód, és minden számkód külön sorba kerüljön!
Mivel a szavak.txt tartalma már a szavak listában van, ezért a már elkészített betuSzama() függvényt felhasználva, minden szót kóddá alakíthatunk és kiírhatjuk a kodok.txt-be. (Ha már most előre olvasod a 7. feladatot láthatod, hogy érdemes lenne egyből egy listát is készíteni a kiírt kódokból, de most úgy viselkedünk, mint az átlagos diák. Nem olvas csak, ha muszáj.)
print("6. feladat")
with open("kodok.txt","w",encoding="utf-8") as kodokFile:
    for egySzo in szavak:
        kod = ""
        for betu in egySzo:
            kod += str(betuSzama(betu))
        kodokFile.write(kod+"\n")
Magyarázat: A "w" paraméter létrehozza és írásra megnyitja a kodok.txt állományt. Az első (külső) ciklus bejárja a szavakat. A kod változót minden szó előtt üres sting-re cserélünk. A belső ciklus a szavak betűit járja be. Minden betűhöz tartozó kódot string-gé konvertálunk és hozzáfűzünk a kod változóhoz. Majd a kész kódsort egy sortörés karakter kíséretében kiírjuk a kodok.txt állományba.
  
7. feladat
Kérjen be a felhasználótól egy számsort, és határozza meg, hogy melyik szó tartozhat hozzá! Amennyiben több szó is megfelelő, akkor mindegyiket írassa ki! (Teszteléshez használhatja például a 225 számsort, mivel ehhez egynél több szó tartozik a szógyűjteményben.
Jé, ez meg egy kiválogatás tétel.

Általános megfogalmazás:

Adott egy N elemű sorozat és sorozat elemein értelmezhető T tulaj-donság. Válogassuk ki egy új B sorozatba az összes T tulajdonságú elemét a sorozatnak.
  
A T sorozatból válogassuk ki a T tulajdonságú elemeket!
bemenet: T[] tömb
i = 0;
j = 0;
N = tömb hossza;
Ciklus amig i < N
   Ha T[i] T tulajdonságú akkor
        B[j] = T[i]
        j++
   i++
Ciklusvége
Először egészítsük ki a 6. feladat kódját. Mint már említettem, ha lenne egy listánk a kódokról, akkor azt ebben a feladatban felhasználhatnánk.
print("6. feladat")
with open("kodok.txt","w",encoding="utf-8") as kodokFile:
     kodok = []
     for egySzo in szavak:
        kod = ""
        for betu in egySzo:
            kod += str(betuSzama(betu))
        kodok.append(kod)
        kodokFile.write(kod+"\n")
Így már van egy kódokat tartalmazó listánk, amelyikben kereshetjük a felhasználó által megadott kódot.
print("7. feladat")
szamSor = input("Kérek egy számsort: ")
joKodok = []
i = 0
for kod in kodok:
    if kod == szamSor:
         joKodok.append(i)
    i += 1
if len(joKodok) > 0:
     for kod in joKodok:
         print(szavak[kod])
else:
     print("Nincs a számsornak megfelelő szó!")
Magyarázat: Bekérünk egy számsort, utána létrehozunk egy üres listát (joKodok). A ciklus végig halad az össes kódon, ha valamelyik egyezik a beírt számsorral azt hozzáfűzzük a joKodok listához. Ha végére érünk a listának, akkor megvizsgáljuk, hogy van-e elem a joKodok listában. Ha a lista elemeinek száma nagyobb, mint nulla, akkor van tehát kiírjuk a képernyőre, különben szólunk, hogy nincs a kódnak megfelelő szó.

8. feladat
Határozza meg, hogy a szógyűjteményben mely kódokhoz tartozik több szó is! Írassa ki a képernyőre ezeket a szavakat a kódjukkal együtt egymás mellé az alábbi mintának megfelelően (a szavak sorrendje ettől eltérhet):

sms02 

1. megoldási javaslat: Végig nézem az összes kódot és megszámolom melyikből hány darab van. Majd kiírom azokat, amelyekből egynél több van. 2. megoldási javaslat: Végig járom az összes kódot, mindegyikből megnézem van-e még több, ha igen kiírom.
Szerintem a második elgondolás az egyszerűbb. Azonban, ha a ). feladatot is elolvasom, akkor rájövök, hogy érdemes egy listába kigyűjteni, hogy melyik szóból mennyi van, mert a 9. feladatban szükség lesz arra a kódra, amelyik a legtöbbször szerepel.
Tehát mégis az első gondolat a jó gondolat. mosoly
No akkor járjuk végig a kodok listát. Minden kódról derítsük ki, hogy hányszor szerepel, majd írjuk ki a szavak és kodok listából azokat, amelyek indexe megegyezik az összesített listában azon elemek indexével, ahol az érték nagyobb, mint 1.
print("8. feladat")
kodOsszesites = []
for kod in kodok:
    kodOsszesites.append(kodok.count(kod))
i = 0
for o in kodOsszesites:
    if o > 1:
        print(szavak[i] + " : " kodok[i] + "; ", end = "")
    i += 1
Persze, ha a kodOsszesites.append(kodok.(kod)) sor helyett egy megszámlálás tételt szeretnéd alkalmazni. Vagyis egy darab = 0 után, egy új ciklussal végigjárod a kodok listát és ha éppen az aktuális kóddal találkozol, akkor növeld a darabszámot eggyel. Majd fűzd a kódOsszesites listához a kapot darabszámot. Nekem jó így is.

9. feladat
Határozza meg, hogy melyik kódnak megfelelő szóból van a legtöbb! Írassa ki a képernyőre a kódot, és a kódhoz tartozó összes tárolt szót! Ha több kódhoz is azonos számú szó tartozik, akkor elegendő ezen kódok közül csak az egyikkel foglalkozni.

Elméleti megoldás
Azért érdemes végig gondolni, mert a python által kínált lehetőségek, már nem rajzolnak ilyen szép tételes megoldást, viszont hatékonyak és az egyszerűségükben a szépség.
Azért gyűjtöttük ki az előbb, hogy melyik kódból mennyi van, mert így egy maximumkiválasztással megtaláljuk a legnagyobbat, majd egy kiválogatással megszerezzük az összes indexét és ezáltal a szavakat is.
# Először megkeressük a legnagyobb számot a kodOsszesites listában, mert ez lesz az a kód, amely legtöbbször előfordult 
max = kodOsszesitett[0]
i = 1
Ciklus amíg i < len(kodOsszesitett)
     if kodOsszesitett > max akkor max = kodOsszesitett[i]
     i ++
Ciklus vége
# Kiválogatjuk azokat az indexeket, amelyek a max értékét hordozza
azonosak = [] #ebben fogjuk tárolni az azonosak indexét
i = 0
Ciklus amíg i < len(kodOsszesitet)
     if kodOsszesitett[i] == max akkor azonosak.append(i)
Ciklus vége
# Már csak ki kell írni az összesített eredményt, legalábbis az elsőt
Kiír: 
Legtöbbször előforduló kód: kodok[azonosak[0]]
i = 0
# Az azonosak listában több is összegyűlhet, ami azonos hosszú, de nekünk csak az elsőre van szükségünk.
Ciklus i < max
      kiír: szavak[azonosak[i]] 
Ciklus vége
Természetesen az előbb vázolt elméleti megoldás, mondatszerű leírással  könnyedén átültethető python nyelvre. A megoldás azonban, ha kihasználjuk a nyelv adta lehetőségeket rövidebb, mert a maximumkiválasztás helyett a max() függvényt használjuk.
print("8. feladat")
legtobbszor = max(kodok)
azonosak = []
i = 0
for egyMax in kodOsszesites:
    if egyMax == legtobbszor:
        azonosak.append(i)
    i += 1
print("A legtöbb szóhoz tartozó azonos számsor pl:: %s"%kodok[azonosak[0]])
for i in range(0, legtobbszor):
    print(szavak[azonosak[i])