12. hét: adatszerkezetek
Czirkos Zoltán · 2024.11.10.
Listák leképezése és szűrése. A dict és set típusok használata.
Felkészülés a laborra:
- A listák leképezése és szűrése témakör megértése.
- A Python beépített tárolóinak ismerete.
Alakítsd az alábbi programrészeket list comprehension kifejezéssé!
l = []
for i in range(0, 10):
l.append(i * 2)
l = []
for i in range(100):
if i % 10 == 3:
l.append(i)
l1 = [43, 15, 48, 59, 33, 72, 11, 65, 95, 34]
l2 = []
for i in l1:
if i % 2 == 1:
l2.append(i)
l1 = [43, 15, 48, 59, 33, 72, 11, 65, 95, 34]
l2 = []
for i in l1:
if i % 2 == 1:
l2.append(True)
else:
l2.append(False)
# Vigyázz, ebben átverés az if.
l1 = ["alma", "körte", "barack", "szilva", "ananász"]
l2 = []
for s in l1:
if s[0] == 'a':
l2.append(s)
l1 = ["alma", "körte", "barack", "szilva", "meggy"]
l2 = []
for s in l1:
l2.append(len(s))
print(l2)
Alább olvashatod Szász Pál versét. A vers érdekessége, hogy a szavak hossza, azaz a betűik száma kiadja a π tizedesjegyeit. Nem → 3, a → 1, régi → 4, és így tovább.
Nem a régi s durva közelítés,
Mi szótól szóig így kijön
betűiket számlálva.
Ludolph eredménye már,
ha itt végezzük húsz jegyen.
De rendre kijő még tíz pontosan,
azt is bízvást ígérhetem.
A feladatod: megkapod a verset az alább látható formában; a sorokat / jellel elválasztva, ahogy azt irodalom óráról ismerjük. Írd ki a vers alapján a π tizedesjegyeit! Használj lista szűrés és leképezés műveleteket!
vers = "Nem a régi s durva közelítés, / Mi szótól szóig így kijön / betűiket számlálva. / Ludolph eredménye már, / ha itt végezzük húsz jegyen. / De rendre kijő még tíz pontosan, / azt is bízvást ígérhetem."
A program ezeket a számjegyeket kell majd kiírja:
3141592653589793238462643383279
Megoldás
vers = "Nem a régi s durva közelítés, / Mi szótól szóig így kijön / betűiket számlálva. / Ludolph eredménye már, / ha itt végezzük húsz jegyen. / De rendre kijő még tíz pontosan, / azt is bízvást ígérhetem."
szamjegyek = [
len(szo.rstrip(",."))
for szo in vers.split()
if szo != "/"
]
print(*szamjegyek, sep="")
A vers.split()
szavakra töri a sztringet a szóközök mentén. Ezzel kapunk egy ehhez hasonló listát:
["Nem", "a", "régi", "s", "durva", "közelítés,", "/", "Mi", ...]
Ebből nekünk a perjelet tartalmazó sztringek nem kellenek, mert azok nem részei a versnek, csak a sorok határait jelölik.
Azaz beteszünk egy szűrést: if szo != "/"
.
A kapott sztringek felesleges írásjeleket is tartalmaznak, amelyek pedig a szavaknak nem részei. Ezeket le kell vágni. Úgyhogy a
feldolgozott szavakból, for szo in vers.split()
, kivágjuk azokat. Ezt a sztringek .rstrip()
tagfüggvénye
tudja megtenni, amelynek most megadjuk, hogy a vesszők és a pontok nem kellenek. Így kapnánk az alábbi listát:
["Nem", "a", "régi", "s", "durva", "közelítés", "Mi", ...]
Ez már nem tartalmaz sem szükségtelen sztringeket, sem szükségtelen karaktereket. Vagyis ebben kell egy leképezést végezni:
minden szó helyett annak hosszát tekinteni. Ezért a szo.rstrip(".,")
kifejezést, amely a szavakat adja, még odaadjuk a
len
függvénynek. És készen is vagyunk, ez a lista kerül a szamjegyek
változóba:
[3, 1, 4, 1, 5, 9, 2, ...]
Az egész feladat egyébként megoldható egyetlen sorban, mert ha az első kifejezésbe írt szo.rstrip(",.")
kifejezést
rögtön len()
-be csomagoljuk, akkor eleve a szóhosszak listája áll elő:
szamjegyek = [len(szo.strip(",.")) for szo in vers.split() if szo != "/"]
Charlie fagylaltot árul: jelenleg pisztácia, vanília, tutti-frutti, karamell, rumos dió és kávé a választék. A fagyit íz alapján kérhetik a gyerekek, egyszerre csak egy gombócot. A készlet véges, minden gombóc eladásával értelemszerűen eggyel csökken.
Tárold el a rendelkezésre álló mennyiségeket egy szótárban, azaz dict
tárolóban!
fagyik = {
"pisztácia": 0,
"vanília": 3,
"tutti-frutti": 8,
"karamell": 4,
"rumos dió": 5,
"kávé": 9,
}
Írj programot, amely a vásárlásokat kezeli! Olvasd be a vásárlásokat (ízeket) üres sorig. Keresd meg az előbb megírt függvénnyel a kapott ízt, és jelezd a vásárlás eredményét: sikeres, vagy kifogyott (volt, de 0-ra csökkent), esetleg nem is volt!
vanília kösz, öcsi! pisztácia pisztácia kifogyott! csokoládé csokoládé nem is volt!
Adott egy zöldséges alábbi raktárkészlete és árai:
keszlet = {
"banán": 6,
"alma": 31,
"narancs": 32,
"körte": 15
}
arak = {
"banán": 100,
"alma": 80,
"narancs": 120,
"körte": 90
}
Első feladat
A programodban egy vásárlást kell kezelni. A felhasználó megadja, hogy mit szeretne venni – több zöldség vagy gyümölcs nevét is megadhatja, egészen üres sorig tart a bemenet. Ezután írja ki a program, hogy mennyi a vásárlás végösszege! Természetesen csökkenjen is a készlet, vagy ha olyan tételt kért, amiből nincsen, akkor jelezze azt a program.
banán OK dinnye Nincs raktáron. alma OK Végösszeg: 180
Második feladat
Adott ugyanez a két tároló. Mennyit ér a raktárkészlet, azaz mennyi pénzt keresne a zöldséges, ha eladná az összeset?
A zheredmeny.txt egy képzeletbeli évfolyam NEPTUN kódjait és dolgozatok eredményeit tárolja. Minden sor egy dolgozat adatait tárolja: NEPTUN kód és pontszám, kettősponttal elválasztva.
DHSF7F:24 ZPD9PY:17 LGNUKG:3 XMOO5D:12 ...
Tudjuk, hogy a NEPTUN kódok egyediek, ezért egy szótárban (dict
típusban) kulcsnak használhatóak.
- Írj függvényt, amelyik beolvassa egy fájlt, és létrehoz egy szótárat. A szótár kulcsai a NEPTUN kódok, értékei pedig a dolgozat pontszámok lesznek.
- Hányan írták meg a dolgozatot? Írd ki a programban a
dict
ismeretében! - Készíts statisztikát, hány pontos dolgozatból hány darab született! Vedd észre, hogy ehhez nem kell ismerni
a minimális és a maximális pontszámot. A szótár „lyukas listának” használható, amiben csak bizonyos indexek
léteznek. Ellenőrzésképp néhány adat:
0: 1 7: 3 25: 2
- Készíts egy másik szótárat is, amely szintén pontszámmal indexelhető, de most nem létszámot, hanem listát
tartalmaz! Pl.
kiknek[7]
azt fogja tárolni, hogy kik azok (mi a NEPTUN kódjuk azoknak), akik 7 pontos dolgozatot írtak. Ellenőrzésképp pár adat:0: ['E3YX24'] 7: ['OI0IO1', 'UPAXFK', 'NDAI3P'] 25: ['IP1WBY', 'K8TOO0']
Írj függvényt, amelyik pontszámok szerint növekvő sorban listáz egy ilyen szótárat! Mivel a szótár elemei össze-vissza
tárolódnak, ezért rendezni kell őket. Kulcsok szerint iterálással, sorted(d.keys())
, vagy
sorted(d.items())
.
Megoldás
def beolvas(fajlnev):
d = {}
with open(fajlnev, "rt") as f:
for s in f:
neptun, pont = s.split(":")
d[neptun] = int(pont)
return d
def hisztogram(d):
"""Pontszámok szerinti hisztogram."""
# Az eredeti szótár értékei a pontszámok.
# Beszúráskor lehet épp új elem jön létre:
# ezt itt a .get() függvénnyel oldjuk meg.
# Az if pont in p esetszétválasztás is jó lenne.
p = {}
for pont in d.values():
p[pont] = p.get(pont, 0) + 1
return p
def kiknek(d):
"""Pontszámok szerinti NEPTUN kód listák."""
# Itt látni kell a pontokat és a NEPTUN kódokat
# is, úgyhogy d.items()-en iterál a ciklus.
# Ha az adott pontszámot még nem láttuk,
# új listát kell létrehozni.
n = {}
for neptun, pont in d.items():
if pont not in n:
n[pont] = []
n[pont].append(neptun)
return n
def print_dict(d):
"""Kulcsok szerint növekvő sorban listáz."""
for key, val in sorted(d.items()):
print("{}: {}".format(key, val))
def main():
d = beolvas("zheredmeny.txt") # { neptun: pont }
print("Létszám:", len(d))
h = hisztogram(d) # { pont: létszám }
print_dict(h)
n = kiknek(d) # { pont: [neptun, neptun, ...] }
print_dict(n)
main()

Egy kutyatenyésztő számára kell programot írnod, amely a kutyákat tartja nyilván. Egy kutyáról a következő adatokat kell megjegyezni: 1) ID, vagyis azonosító, egész szám, 2) név, 3) papa és 4) mama, a kutya szüleinek azonosítói, vagy -1 értékek, ha ismeretlenek.
Mivel egy kutyát mindig ID alapján kell megtalálni, ezért tárolhatod őket egy dict
-ben. Pl. az 5-ös azonosítójú
kutya a doges[5]
lesz:
doges = {}
doges[5] = Doge(5, "Woof")
doges[7] = Doge(7, "Floof")
Így bár úgy viselkedik, mint egy lista, de az indexek akármilyen egész számok lehetnek.
Az alábbi részfeladatok megvalósítása után mindig teszteld a megírt programrészeket!
- Definiáld a
Doge
osztályt! - Írj függvényt, amelyik kiírja az összes tárolt kutya nevét és azonosítóját!
- Írj függvényt, amely egy a paraméterként kapott tárolóban megkeresi a szintén paraméterként kapott azonosítójú kutyát! A
visszatérési érték a megtalált elem, vagy
None
. Teszteld ezt olyan módon, hogy a felhasználótól kérsz azonosítókat! - Írj függvényt, amely egy megadott azonosítójú kutyát töröl a tárolóból! Figyelj arra, hogy ilyenkor át kell vizsgálni az adatbázist: ha a törölt listaelemet valamelyik másik elem szülőként (papa, mama) hivatkozza, akkor azoknál -1-et kell beírni.
- Írj függvényt, amely a paraméterként kapott nevű szöveges fájlba kiírja a kutyák adatait, soronként id, név, papa id, mama id formában, szóközökkel elválasztva. Ha ismeretlenek a szülők, az azonosítók helyére a fájlban is -1 kell kerüljön.
- Írj függvényt, amely visszaolvas egy ilyen fájlt, betölti onnan a kutyák adatait!
Ha a laborfeladatokkal elkészültél, dolgozz a példatárban lévő feladatokon, a szorgalmi feladatokon, a minta vizsgán, vagy a házi feladatodon.
Informatikusok próbálják lekódolni az Algoritmusok és gráfok tárgyon tanult algoritmusokat. Ezzel két legyet lehet ütni egy csapásra, mert két tantárgyat is gyakoroltok egyszerre.