Megpróbálkozunk egy ilyennel is. Idén kezdve az egyetemet megkezdődött a Szoftvertervezés és fejlesztés című tantárgy, melynek gyakorlati részén a C# nyelv csodáival foglalkozunk. Nos az első félév jó részében annyira kell tudni programozni, mint amennyire az érettségiben is ajánlott, hogyha a maximális pontot akarod megszerezni. Az OOP-t leszámítva, ha jól láttam amit a félévben tanulnánk már szükséges volt az érettségihez, így gondoltam arra, hogy aki idén, vagy akár későbbi években vetemedik rá az emelt érettségi lerakásának, annak szeretnék minimálisan segíteni abban, hogy mivel én is raktam le emelt infó érettségit és végigcsináltam az összes évi feladatsort, így szintfenttartásképp egy-két C# érettségi feladatot megoldok és a megoldást itt a honlapon, valamilyen szinten próbálom elmagyarázni.

Fontos, hogy akkor nézegesse ezt valaki, hogyha már volt tapasztalata valamennyire programozás terén, ugyanis nem a C#-ot akarom magyarázni, hanem sokkal inkább a logikát, vagy módszert amivel egy-egy feladatot meg lehet oldani. Természetesen végtelen számú megoldás létezik, ezek csak az én nézőpontomból vannak, előfordulhat hogy más egyszerűbben, vagy bonyolultabban oldaná meg. Én a poszt miatt megcsináltam mégegyszer a 2016. évi emelt érettségi feladatot, melyben egy bolt pénztárában történt vásárlásokról van egy lista. Törekedtem arra, hogy ne legyen túlbonyolítva, így könnyen értelmezhető legyen és ne használjak túl sok C# specifikus elemet. Egyedül a végén lévő 2 feladatnál használtam listát, mivel így egyszerűbb volt megoldani a feladatot és ránézésre is érthetőbbnek néz ki.

Na de vágjunk is bele!

Oktatási Hivatal oldalán a 2016-os emelt érettségit kikeresve találjuk meg a forrást, illetve a feladatlapot is.

Feladatlap: http://dload.oktatas.educatio.hu/erettsegi/feladatok_2016tavasz_emelt/e_inf_16maj_fl.pdf

Forrás: https://www.oktatas.hu/bin/content/dload/erettsegi/feladatok_2016tavasz_emelt/e_inffor_16maj_fl.zip

Először is a zipben található penztar.txt fájlt másoljuk be a projekt Debug mappájába.

Első feladat

Olvassa be és tárolja el a penztar.txt fájl tartalmát!

Az előbb bemásolt txt fájt be kell olvasnunk, így hát a fájl elején lévő using System; és egyéb dolgokhoz egy új sorba írjuk be a using System.IO;-t. Így fogunk tudni használni fájlműveletekhez kitalált metódosokat. Innentől kezdve neki is állhatunk a fájl beolvasásának. Először is meg kell határoznunk, hogy mit is szeretnénk beolvasni. Ide beszúrom most a fájlbeolvasáshoz szükséges kódrészletet, alatta magyarázom a sorokat.

Az első sorban létrehozunk egy StreamReader objektumot. Ez ugyanolyan mintha egy változó lenne, csak ez nem szöveg, szám, vagy akármi, hanem ez egy fájlt “tárol”. Így deklarájuk és ahogy láthajuk a végén levő idézőjeles részben adjuk meg, hogy mit olvasnánk be. A feladatlap kitér rá, hogy maximum 1000 sor lehet a fájlban, de sokkal egyszerűbb lesz később, ha meghatározzuk hány sort tartalmaz a fájl. Ehhez felvettem egy sorokSzama nevű számváltozót és egy vasarlasokSzama elnevezésűt is. Utóbbit azért, mivel úgy határozzuk meg a sorok számát, hogy végighaladunk a fájl sorain és megszámoljuk közben, hogy ezekből mennyi van.

Mivel a feladatlapon az van, hogy az egyes vásárlások végén a fizetés a fájlban külön sorban betűvel van jelezve, így adja magát, hogy miért ne ütnénk 2 legyet egy csapásra. Tehát miközben megszámoljuk a sorokat, közben megnézzük azt is, hogy ha az épp beolvasott sor, tehát az sr.ReadLine() értéke megegyezik a nagy F betűvel akkor növeljük a vásárlások számát.

Fontos, hogyha nem vizsgálnánk a vásárlások számát és azt a részt csak úgy kitörölnénk és a while ciklusban csak a sorokSzama++ maradna, akkor sose lenne vége a számlálásnak, ugyanis a program az sr.ReadLine() meghívásakor olvas be egy sort és ugrik a következőre. Így hát ha egy más esetben csak a sorok számát vizsgálnánk akkor is egy üres sorba, csak írjuk bele az sr.ReadLine()-t.

Nem értünk a feladat végére, ugyanis még nem olvastunk be semmit. Lássuk hát a feladat megoldásának a folytatását:

Felveszünk 2 szám típusú változót. Egyik a ciklusban a vásárlás sorszámát, míg a másik a vásárláson belüli árucikk sorszámát fogja jelölni. Továbbá felveszünk egy olvasottSor elnevezésű szöveges változót, abban az aktuálisan beolvasott sort fogjuk eltárolni. Szükség lesz ezen felül egy 2 dimenziós tömbre, vagy ha úgy tetszik mátrixra. Ebben fogjuk eltárolni az összes vásárlást és később is ezzel fogunk dolgozni. A tömb hosszúságának az első értéke, a vásárlások száma lesz, míg a második pedig 20. Az első indexben lesz mindig a vásárlás szorszáma és a második indexben pedig a vásárolt árucikk sorszáma. A tömb második dimenziójának a maximális hossza azért 20, mert a feladatlapon az található, hogy egy vásárlás alkalmával maximum 20 árucikket vásárolhatnak. Lehet, hogy van olyan vásárlás amikor akár fele, vagy negyed ennyit sem vesznek, de mivel a tömb mérete nem dinamikus így a legrosszabb esettel kell számolnunk. Persze megnézegethettük volna itt is, hogy melyik vásárlásnál volt a legtöbb árucikk megvéve és ott mennyi és amennyiben az kevesebb 20-nál akkor csak annyira korlátozni a tömböt, de felesleges bonyolítás lett volna, úgyhogy inkább azt hagytam.

Van most egy érdekes sor. sr.BaseStream.Position = 0. Mi ez? Mivel korábban már végigjártuk a fájlt, az sr változónkban, jelenleg a fájl legvégén vagyunk, így aztán, hogy ismét végigjárjuk, vissza kell mennünk a fájl elejére és ezt teszi meg az alábbi kódsor.

Ismét az előbb is használt while ciklus amivel végigmegyünk a fájlon. Az aktuálisan olvasott sort eltároljuk az imént deklarált változóban és a későbbiekben azt használjuk. Erre azért van szükség, ugyanis ahogy láthatod, 2 helyen van utána használva az olvasottSor. Ha helyette oda sr.ReadLine()-t írnánk, akkor a második alkalommal már beolvasna egy újabb sort és azzal dolgozna. Erre nem árt figyelni.

Amit tehát itt láthatunk az az, hogy végigmegyünk a sorokon. Kezdetben a tömbünk mindkét indexe 0. Nézünk egy sort. Ha abban a sorban csak egy F betű van, akkor a tömb első indexének számlálóját növeljük és a második index számolóját pedig nullázzuk. Ugye az első index adja meg a vásárlás sorszámát, a második pedig a termék sorszámát egy vásárláson belül. Ha az F-hez érünk az épp beolvasott vásárlás befejezettnek tekinthető, tehát ilyenkor nullázuk az éppen végighaladott árucikk számolóját, mivel új vásárlás fog ezután következni, így 0-ról kell indulnia megint. Az első index számolóját pedig növeljük eggyel, ugyanis egy következő vásárlást fogunk eltárolni.

Ha pedig nem F van az épp vizsgált sorban

Az aktuális vásárlás sorszámával és az aktuálisan beolvasott termék két számolójának értékével bemegyünk a tömbbe és ott eltároljuk a beolvasott sort. Tegyük fel, hogy épp a szamolo értéke 5 és a belsoSzamolo értéke pedig 2. Nem F az aktuális sor, tehát még nem ért véget a vásárlás, terméket tárolunk el. Így hát a !NEGYEDIK! vásárlás !HARMADIK! eleme az épp vizsgált sor értéke lesz. Utána megnöveljük a belsoSzamolo értékét eggyel, hogy a következő vizsgált sor, ha termék, akkor ne írja fel ezt.

Ha sikerült megérteni, akkor király és jöhet az öröm, mert megvagyunk az első feladattal. Ha nem tiszta a dolog, akkor kísérletezgetni kell vele, esetleg mégegyszer végigolvasni.

Második feladat

Határozza meg, hogy hányszor fizettek a pénztárnál!

Hahajjjjj! Micsoda királyok vagyunk mi! Ugye-ugye! Volt értelme szenvedni az első feladattal, ugyanis most sokkal könyebb lesz a feladatunk. Nem csak kettő, hanem három legyet is ütöttünk egy csapásra. Ezért jó, ha próbálunk előre gondolni és előre megcsinálni dolgokat még akkor amikor egyszerűbb.

Ugye mi a beolvasásnál, hogy ne legyen túl nagy a tömbünk első indexe, megnéztük hány vásárlás van összesen és csak akkora lett az első index maximális hossza. Így aztán a legegyszerűbb mozdulattal, csak ki kell írnunk ezt a változót. Ennyi az egész:

Harmadik feladat

Írja a képernyőre, hogy az első vásárlónak hány darab árucikk volt a kosarában!

for-cik-lus

Felveszünk egy számolót, aminek beállítjuk 0-ra az értékét. Ebben fogjuk tárolni, hogy az első vásárló kosara hány terméket tartalmazott.

Belövünk egy for ciklust, ami 0-tól 19-ig megy, mivel ennyi elemet kell megvizsgálnunk az első vásárlásnál. Adott, hogy az tömböt ha vizsgáljuk, az első index 0 lesz, mivel az első sorra vagyunk kíváncsiak. Tovább 0-19-ig indexelt oszlopok pedig egy-egy árucikket fognak tartalazni. De nem biztos, hogy mind a 20 helyen van egy árucikk, így a for cikluson belül megnézzük, hogy az éppen vizsgált elem biztosan nem üres-e, ezt stringnél a != null -al tudjuk megtenni. Ha pedig nem üres akkor, inkrementáljuk a változót, majd a for ciklus befejezte után kiírjuk azt. Easy.

Negyedik feladat

Kérje be a felhasználótól egy vásárlás sorszámát, egy árucikk nevét és egy darabszámot!
A következő három feladat megoldásánál ezeket használja fel!

Egyértelmű, ezzel majd csak később kell szenvednünk, de most még kedvesek és megkímélnek annyival, hogy elég ha csak bekérjük a későbbiekhez az adatokat a felhasználótól.

Szerintem nem igényel nagy magyarázatot. A felhasználótól bekért információ mindig string típusú lesz, hogy most azt ki milyen módszerre varázsolja int típussá, az most lényegtelen. Fontos, hogy szám típusú változóban tárold el, mert később is úgy tudsz vele dolgozni, valamint úgy korrekt ha a számot számként tárolod el és persze valószínűleg javításnál is akkor kapsz rá pontot.

Ötödik feladat

Határozza meg, hogy a bekért árucikkből
a. melyik vásárláskor vettek először, és melyiknél utoljára!
b. összesen hány alkalommal vásároltak!

Három dolgot kérdeznek, tehát mi is annyi változót hozunk létre. Tipikus kérdés, úgyhogy ezt jó megtanulni mert szinte minden alkalommal kérdeznek ilyen mikor először, mikor utoljára, vagy minimum-maximum dolgot.

Itt már a for ciklus bonyolódik, ugyanis az összes vásárlás összes termékét kell vizsgálnunk, tehát mindkét dimenziót be kell járnunk. Az i számolós for ciklus az első, a j számolós pedig a második dimenzión megy. Kívűl van tehát a vásárlás és azon belül a vásárolt árucikk logikusan.

Megyünk tehát végig a vásárlásokon és azokon belül az árucikkeken és nézzük azt, hogy az aktuálisan vizsgált vásárláson belüli árucikk megegyezik-e azzal amit mi megadtunk. Rögtön, ha még az arucikkElso nem kapott semmit, tehát nulla, akkor gyorsan meg is kapja azt az értéket, ami épp az i változóban van. Azért azt,mert az i változó jelöli az épp vizsgált vásárlás sorszámát. Ehhez hozzáadunk egyet, mivel a C# 0-tól indexel, az ember pedig nem. arucikkUtolso barátunkkal pedig nem csinálunk semmit, csak mindig megkapja az i változó eggyel növelt értékét, így ha lezárul a for ciklus, annak a vásárlásnak a sorszámát fogja tárolni, amelyikben utoljára megtalálható volt a keresett árucikk. És mivel növekvő sorrendben haladtunk, így az is lesz az utolsó vásárlásé. arucikkCount-ot meg talán nem kell túlmagyarázni, hogy hogyan működik. Végén pedig kiírjuk a dolgokat mint eddig. Én azért nem csinálok ilyen + ” aaa ” + valtozo szerű dolgokat, tehát amikor így összefűzünk dolgokat, mert szerintem átláthatatlanabb a dolog, figyelni kell az idézőjelekre, a plusszokra, így meg csak a végén végigirogatjuk a változókat.

Hatodik feladat

Határozza meg, hogy a bekért darabszámot vásárolva egy termékből mennyi a fizetendő
összeg! A feladat megoldásához készítsen függvényt ertek néven, amely a darabszámhoz
a fizetendő összeget rendeli!

Innentől kezdenek bonyolódni a dolgok. Létre kell hoznunk egy saját függvényt, amit erteknek kell nevezünk és egy megadott darabszám alapján megadja a fizetendő összeget. Minden termék ugyanannyiba kerül, így ezzel nem kell számolnunk csak a darabszámmal. Ha visszakukkantunk a feladatlap elejére, láthatjuk, hogy ha ugyanabból a termékből többet veszünk, akkor az első még 500 valamibe, a második 450-be és a harmadiktól kezdve minden további termék már csak 400 valamibe kerül. Ha nem kéne rá írni függvényt, akkor is azt mondanám, hogy írjunk egyet, mert a későbbi feladatokban szükség lesz rá, hogy ugyanígy határozzunk meg fizetendő összeget, tehát jobb ha egyszer van leírva, mint folyton másolgatva és variálgatva. Egyébként is érdemes úgy kezdeni a megoldást, hogy végigolvasni az összes feladatot, végiggondolni, hogy mire lesz szükség és mi az amit akár egyben le lehet tudni, hogy időt és energiát spóroljunk.

Na de álljunk is neki a függvénynek. Egy függvényt a Program osztályon belül hozunk létre. Akár a a Main() függvény elé, ahol maga a programunk hajtódik majd végre. Most bemásolok egy olyan részletet, ahol nem csak a hatodik feladat megoldása van, hanem az előtte és mögötte lévő pár sor, hogy lássuk, hova is kéne ezt írni.

Csinálunk hát egy olyan függvényt ami számot ad vissza. Ezt még a függvény elnevezése előtt egy int beírásával tesszük meg, ahogy látható. A zárójeles részben megadjuk, milyen adatot vár tőlünk majd a függvény. Jelen esetben a függvénynek tudnia kell, hogy mekkora vásárolt mennyiségre mondja meg mennyit kell fizetni, így várni fog egy mennyiseg nevezetű szám típusú változót.

Csinálunk egy null értékű osszeg változót amiben eltároljuk majd a fizetendő összeget. Tovább haladva ha beírt mennyiség nagyobb VAGY EGYENLŐ egy, akkor az összeg 500 lesz. Tovább, ha a beírt mennyiség nagyobb VAGY EGYENLŐ kettő, akkor az összeghez hozzáadunk 450-et. Ha pedig a beírt mennyiség nagyobb VAGY EGYENLŐ három, akkor az összeghez hozzáadunk (mennyiség-2) x 400-at. Ha nem egyértelmű, hogy miért így van, akkor érdemes fejben végigmenni rajta, hogy adott mennyiség értékeknél melyik if-ek hajtódnak végre és akkor biztosan kitisztul a kép. Nekem is úgy ment 😀

Végül pedig visszaadjuk az osszeg változót, tehát a kiszámolt összeget.

Ja és ne felejtsük el, hogy ki kell írnunk, hogy a korábban bekért darabszám alapján mennyit kéne fizetni, szóval:

Hetedik feladat

Határozza meg, hogy a bekért sorszámú vásárláskor mely árucikkekből és milyen
mennyiségben vásároltak! Az árucikkek nevét tetszőleges sorrendben megjelenítheti.

Itt lesz érdekes az egész. Ha a függvényes dolog már bonyolultnak tűnt akkor ez sajnos mégrosszabb lesz. Egyébként így leírva sokkal bonyolultabbnak tűnik, mint akár videóban, akár szóban. Pláne úgy, ha te magad jössz rá és csináld meg, akkor onnan visszagondolva rettentő egyszerű a dolog. Csak így magát a nyers kódot látva kicsit ijesztő és bonyolult lehet, pedig ha nekiállsz ilyen érettségis feladatokat csinálni akkor néhányadik után már elég egyszerű lesz, főleg, hogy mindegyik szinte ugyanarra a sémára épül. Ezt így kedvjavítónak, hogy ne most zárd be a Chrome lapot amikor meglátod a kódot.

Mi a szűzmária az a List<>??? Na most vagy tudsz róla, vagy ugyanúgy felsikítottál ahogy megláttad, de fő a nyugalom. Röviden, tömören és főképp egyszerűen mondhatjuk azt, hogy a List ugyanaz, mint egy tömb, csak itt nem kell megadni, hogy milyen hosszú legyen, hanem dinamikusan növelhető. Azért döntöttem emellett, mert itt már teljesen random, hogy egy adott vásárlásnál hány termék van és a termékekből melyik az ami ugyanaz és mivel nincsenek a termékek ABC szerint rendezve, így egyszerűbbnek találtam, ha így csinálom. Talán így a leggyorsabb és legérthetőbb.

Létrehozunk kapásból 2 Listát. Nos bevallom azért, mert nem tudom hogy van-e egyáltalán a Listből 2 dimenzós változat. Meg hát amúgy is a mennyiség az szám, a termék pedig szöveg, szóval mivel úgysem ugyanaz a típusuk egyszerűbb is így. Tehát az egyik listában egy adott termék neve lesz, egy másik listában pedig a termékhez tartozó mennyiség. Az a cél, hogy megcsináljuk azt, hogy a vásárláskor megvásárolt termékekből, “összecsoportosítsjuk” azokat amik ugyanazok és azokat csak egyszer tároljuk el, de mellé legyen ott, hogy abból a termékből mennyi lett véve. Ha például veszünk 2 tulipán és egy kerékcsapágyat, akkor felírhatjuk úgy, hogy amit vettünk az 2 tulipán és 1 kerékcsapágy, vagy felsorolhatjuk, hogy tulipánt, tulipánt és kerékcsapágyat vettünk. Ez tehát a cél. A logika az, hogy végigmegyünk a vásárolt termékeken. Megnézzük, hogy az épp vizsgált termék szerepel-e már a listában és ha nem, akkor hozzáadjuk. Viszont ha már szerepel benne, akkor nem adjuk hozzá mégegyszer, csupán a mennyiségét növeljük meg eggyel. Ez a gyakorlatban felül látható.

Sima egyszerű for ciklus, végigmegyünk vele korábban a felhasználótól bekért vásárlás sorszámán. Mivel lehetnek null értékű helyek a tömbben, ezért itt is itt a szokásos if. Most jön egy érdekes vizsgálat, ilyen még nem volt és ezért egyszerűbb ezt a feladatot Listával megcsinálni szerintem, mert nem kell végigmennünk folyton a tömbbön és nézegetni össze-vissza. Tudjuk vizsgálni közvetlen, hogy a termek listánk TARTALMAZZA-az éppen vizsgált terméket, és ha igen, akkor a .Add segítségével hozzáadjuk. Nem kell foglalkozni vele, hogy melyik indextől van üres helyünk, vagy hasonló, itt elintéz helyettünk mindent a lista. Ha új termékről van szó, akkor a terméket hozzáadjuk a termek listához, a mennyiseghez pedig csak egy egyest. Így tehát hiába van 2 különálló listánk, a kettő indexelése ugyanaz lesz.

Ha pedig tartalmaz ilyen terméket már a listánk, akkor ismét egy tök hasznos dologgal, a .IndexOf segítségével, ő magától kideríti nekünk, hogy a keresett elem, tehát a vizsgált termék, ami már biztosan egy már bekerült termék merre van, megkeresi nekünk a program az indexét és azzal az indexxel bent lévő elemet megnöveljük eggyel.

Ha így végiggondoljuk szerintem egyértelmű már, hogyan is megy a mutatvány. Főleg akkor fogunk örülni a fejünknek, amikor nagy lelkesedésünkben ugyanezt meg akarjuk valósítani tömbbel és akkor szívunk az elcseszett indexeléssel, a rengeteg utánakereséssel, meg olyan dologgal amivel feleslegesen idegesítjük magunkat és húzzuk az időt. Persze van olyan, hogy tömbbel kell megcsinálni, vagy úgy jobb. De jelen esetben szerintem egyszerűbb és átláthatóbb így, valamint sokkal kevesesbb lehetőséget hordoz magában arra, hogy valamit úgy csesszünk el, hogy végig azthittük, hogy minden király, de mégsem azt az eredményt dobja amit a végén kéne.