A Bevezetés az R programozási nyelvbe sorozat írásai egymásra épülnek. Aki most ismerkedik az R-rel, annak erősen ajánlom, hogy a korábbi blogposztokkal kezdje. A sorozat eddig elkészült tagjai:
- Vektorok
- Adatkeretek
- Listák
- Vezérlési szerkezetek
Az alábbiakban R nyelven (v4.1.2) írt kódot használok a feladat végrehajtásához. A magyarázó szövegek közé ékelt fekete kódblokkok tartalmát az RStudio-ban egymás alá illesztve elvileg bárki által reprodukálható az itt bemutatott műveletsor. A kódblokkok # kezdetű sorai pusztán magyarázó funkcióval bírnak, ezekre a program futtatásakor nincs szükség.
Feltételes utasítások (if … else)
A programozás során gyakran előfordul, hogy egy kódrészletet csak abban az esetben akarunk végrehajtani, ha teljesül valamilyen általunk meghatározott feltétel. Ha nem teljesül, akkor az adott kódrészlet lefuttatása elmarad, illetve más kódrészlet kerül helyette végrehajtásra.
A feltételes utasítások esetében tulajdonképpen egy döntési szituáció elé állítjuk az éppen futó programot. Előre megadunk bizonyos feltételeket és ezeknek megfelelő folytatási lehetőségeket. A programunknak tehát többféle kimenetele lehet, attól függően, hogy az aktuális feltételrendszer kiértékelése során milyen eredményt kapunk.
Nézzük meg mindezt a gyakorlatban is! Ehhez elöljáróban létrehozok két vektort, amelyekben az Európai Unió és a NATO tagállamai vannak felsorolva.
|
|
## [1] 27
|
|
## [1] 30
Az alábbi kódrészletben az eldöntendő kérdés az lesz, hogy egy konkrét állam tagja-e az EU-nak? Ha a válasz igen, akkor szöveges megerősítést kapunk az adott ország tagságáról. Ha nem, akkor egyelőre nem történik semmi.
Egy feltételes utasítás alapesetben így néz ki: if (feltétel) {kódblokk}
Ha a feltétel értéke TRUE, akkor végrehajtódik a kódblokk tartalma, ha FALSE, akkor viszont nem. Ezeket a logikai értékeket megadhatjuk direktben is, de sokkal gyakoribb, hogy egy logikai kifejezéssel állítjuk elő őket.
|
|
## [1] "Magyarország tagja az EU-nak."
|
|
Ahogy látható, a nem EU tag Szerbia esetében nem történt semmi. Lehetőségünk van azonban arra, hogy egy “egyébként” (else) ágat is beiktassunk a feltételes utasításba. Ennek a kódblokknak a tartalma akkor hajtódik végre, ha a feltétel nem teljesül. A kód szintaxisa most a következő: if (feltétel) {kódblokk} else {kódblokk}
|
|
## [1] "Szerbia nem tagja az EU-nak."
Egy utasításon belül több feltétel is megvizsgálható: if (feltétel) {kódblokk} else if (feltétel) {kódblokk} else {kódblokk}
Ebben az esetben akárhány “egyébként ha” (else if) ágat megadhatunk, a végén lévő “egyébként” ág viszont opcionális. Amennyiben elhagyjuk és nem teljesül feltételek egyike sem, akkor nem történik semmi.
|
|
## [1] "Albánia tagja a NATO-nak."
|
|
## [1] "Magyarország tagja az EU-nak."
Látható, hogy bár Magyarország tagja az EU-nak és a NATO-nak is, de csak EU tagként jelenik meg. Ennek oka a következő:
A több ágat tartalmazó feltételes utasításnál mindig az a kódblokk hajtódik végre, amelyiknél a feltétel elsőként teljesül. A feltételrendszer megfogalmazásánál érdemes alaposan átgondolni a szóba jöhető lehetőségeket és azok sorrendjét.
Logikai operátorokkal összekapcsolva olyan logikai kifejezéseket írhatunk, amelyek egyszerre több szempontot is figyelembe vesznek. Mondjuk azt, hogy egy ország tagja-e mindkét szervezetnek. Nézzünk minden eshetőségre egy-egy példát! (Ez ebben a formában, a kód többszöri leírásával nem túl elegáns megoldás. Később majd finomítunk rajta.)
|
|
## [1] "Magyarország tagja az EU-nak és a NATO-nak is."
|
|
## [1] "Amerikai Egyesült Államok csak a NATO-nak a tagja."
|
|
## [1] "Ausztria csak az EU-nak a tagja."
|
|
## [1] "Szerbia nem tagja egyik szervezetnek sem."
A feltételes utasítások egymásba ágyazhatók. Tehát a kódblokkokban akár újabb feltételes utasítások is szerepelhetnek, ezáltal tovább árnyalva az adott feltételrendszer kínálta lehetőségeket.
Végezetül megemlítem még, hogy bizonyos esetekben az ifelse(feltétel, haIgaz, haHamis)
függvényt is használhatjuk. Ekkor a függvény paramétereként kell megadni a magát a feltételt, valamint azt is, hogy ennek kiértékelése után mi történjen. Ezt a megoldást nyilván csak akkor érdemes alkalmazni, ha egy szimpla eldöntendő kérdésünk van. Egy bonyolultabb feltételrendszernél jobban járunk a fentebb elmondottakkal.
|
|
## [1] "Szerbia nem tagja az EU-nak."
Ismétlések előre ismert számú alkalommal (for)
Igen gyakran előfordul, hogy bizonyos utasításokat több alkalommal is le akarunk futtatni. Hiszen végső soron a programozás lényege az, hogy automatizáljuk a feladatokat. Ilyenkor rendszerint más-más bemeneti értékekkel dolgozunk, s ezeknek megfelelően más-más kimenetet várunk, de maga a művelet lényege viszont azonos.
Ha előre el tudjuk dönteni, hogy hányszor akarjuk lefuttatni az adott utasítást, akkor a for (változó in vektor) {kódblokk}
szintaxist kell használnunk. Itt a kódblokk tartalma annyi alkalommal fog lefutni, ahány eleme van a vektornak. Menet közben a változó mindig felveszi a vektor soron következő elemének megfelelő értéket, amire szükség esetén a kódblokkban hivatkozni tudunk.
Az ismétlések használatának értelmét demonstrálandó, gondoljunk vissza arra a fentebbi példára, amikor egy komplex feltételrendszer alapján az algoritmus eldöntötte, hogy egy-egy ország milyen kapcsolatban van az EU-val és/vagy a NATO-val. Ha megnézzük a kérdéses algoritmust, akkor láthatjuk, hogy az egyébként azonos feltételrendszert minden egyes futtatás alkalmával le kellett írni. Jelen esetben ezt szeretnénk kiküszöbölni.
Az alábbiakban egy vektorban adom meg a tesztelendő országokat. Ezen a vektoron végigmegy az algoritmus, és minden elemén elvégzi a tesztet.
|
|
## [1] "Magyarország tagja az EU-nak és a NATO-nak is."
## [1] "Amerikai Egyesült Államok csak a NATO-nak a tagja."
## [1] "Ausztria csak az EU-nak a tagja."
## [1] "Szerbia nem tagja egyik szervezetnek sem."
## [1] "Koszovó nem tagja egyik szervezetnek sem."
## [1] "Svédország csak az EU-nak a tagja."
## [1] "Albánia csak a NATO-nak a tagja."
## [1] "Görögország tagja az EU-nak és a NATO-nak is."
Az ismétléses ciklussal tehát jelentősen lerövidíthető egy kód, hiszen – a példánknál maradva – akkor is csak egyszer kellene leírni a feltételrendszert, ha a Föld összes országát be akarnánk vonni a tesztbe.
Ugyancsak gyakori alkalmazási területe a for ciklusnak, amikor egy táblázat sorain akarunk végigmenni azért, kiolvassuk, illetve feltöltsük annak valamely celláját.
Ennek kipróbálásához létrehozok egy adatkeretet két oszloppal. Az egyik oszlopba az EU országainak neve szerepel majd, a másikba egyelőre NA értékek kerülnek.
|
|
## orszagNev veletlenSzam
## 1 Ausztria NA
## 2 Belgium NA
## 3 Bulgária NA
## 4 Ciprus NA
## 5 Csehország NA
## 6 Dánia NA
## 7 Észtország NA
## 8 Finnország NA
## 9 Franciaország NA
## 10 Görögország NA
## 11 Hollandia NA
## 12 Horvátország NA
## 13 Írország NA
## 14 Lengyelország NA
## 15 Lettország NA
## 16 Litvánia NA
## 17 Luxemburg NA
## 18 Magyarország NA
## 19 Málta NA
## 20 Németország NA
## 21 Olaszország NA
## 22 Portugália NA
## 23 Románia NA
## 24 Spanyolország NA
## 25 Svédország NA
## 26 Szlovákia NA
## 27 Szlovénia NA
A feladat az, hogy soronként végigmenve a táblázaton, a veletlenSzam nevű oszlop adott cellájába bekerüljön egy 0 és 100 közötti, véletlen módon legenerált szám. A for ciklusban megadott vektor ebben az esetben az 1 és 27 közötti egész számokat tartalmazza – mivel annyi sora van az adatkeretnek, ahány tagállammal rendelkezik az EU. Az i nevű változó ezeket az értékeket fogja felvenni. Tehát mindig az adatkeretünk i-edik sorát manipuláljuk.
A for ciklusban szereplő változó, ha indexelésre használjuk, akkor általában az i vagy j nevet szokta kapni. Ez egy kódolási konvenció. Hogy honnan ered és mi értelme van, arról a vélemények megoszlanak... (Természetesen ettől minden további nélkül el lehet térni.)
A véletlenszámot a runif(n, min, max)
függvénnyel állítom elő, amely a min és max paraméterekben megadott értékek között n darab számot generál le.
|
|
## orszagNev veletlenSzam
## 1 Ausztria 67.112055
## 2 Belgium 13.606211
## 3 Bulgária 30.652120
## 4 Ciprus 79.749580
## 5 Csehország 25.629975
## 6 Dánia 24.723734
## 7 Észtország 24.241574
## 8 Finnország 90.762538
## 9 Franciaország 74.101231
## 10 Görögország 11.756951
## 11 Hollandia 56.516578
## 12 Horvátország 2.247903
## 13 Írország 16.851541
## 14 Lengyelország 77.294379
## 15 Lettország 6.675972
## 16 Litvánia 20.943106
## 17 Luxemburg 34.030423
## 18 Magyarország 19.629212
## 19 Málta 59.953689
## 20 Németország 11.194048
## 21 Olaszország 33.440416
## 22 Portugália 8.419839
## 23 Románia 34.638607
## 24 Spanyolország 88.929126
## 25 Svédország 5.281077
## 26 Szlovákia 43.303897
## 27 Szlovénia 52.614983
Ismétlések előre nem ismert számú alkalommal (while)
Előfordulhat az is, hogy egy utasítássorozatot addig akarunk ismételgetni, amíg egy bizonyos feltétel fennáll. Ennek szintaxisa a következő: while (feltétel) {kódblokk}
Amennyiben a feltétel értéke TRUE, akkor végrehajtódik a kódblokk tartalma, ha FALSE, akkor nem. Ezeket a logikai értékeket direktben vagy egy logikai kifejezéssel tudjuk megadni.
Elképzelhető tehát, hogy az algoritmusunk igen sokáig fog futni. De az is lehetséges, hogy el sem indul, mert a megadott feltétel már eleve hamis.
Az alábbi algoritmus véletlenszerűen kiválaszt egy EU tagországot és megnézi, hogy az tagja-e a NATO-nak is. Amennyiben igen, akkor választ egy másikat. Ez addig ismétlődik, amíg nem talál egy olyan államot, amely csak az EU-nak a tagja.
Az algoritmust három alkalommal is lefuttatom annak érdekében, hogy lássuk, minden esetben más mennyiségű országot kaptunk.
|
|
## [1] "Mindkét szövetségi rendszer tagja: Belgium"
## [1] "Mindkét szövetségi rendszer tagja: Portugália"
## [1] "Mindkét szövetségi rendszer tagja: Dánia"
## [1] "Csak az EU tagja: Finnország"
|
|
## [1] "Mindkét szövetségi rendszer tagja: Csehország"
## [1] "Mindkét szövetségi rendszer tagja: Portugália"
## [1] "Mindkét szövetségi rendszer tagja: Szlovákia"
## [1] "Csak az EU tagja: Finnország"
|
|
## [1] "Mindkét szövetségi rendszer tagja: Dánia"
## [1] "Mindkét szövetségi rendszer tagja: Lengyelország"
## [1] "Mindkét szövetségi rendszer tagja: Spanyolország"
## [1] "Mindkét szövetségi rendszer tagja: Szlovákia"
## [1] "Mindkét szövetségi rendszer tagja: Hollandia"
## [1] "Mindkét szövetségi rendszer tagja: Észtország"
## [1] "Mindkét szövetségi rendszer tagja: Görögország"
## [1] "Mindkét szövetségi rendszer tagja: Magyarország"
## [1] "Mindkét szövetségi rendszer tagja: Lengyelország"
## [1] "Mindkét szövetségi rendszer tagja: Bulgária"
## [1] "Mindkét szövetségi rendszer tagja: Románia"
## [1] "Csak az EU tagja: Finnország"
A feltételes utasításokat és az ismétlődéseket természetesen tetszőleges mélységben egymásba ágyazhatjuk. Ez lehetővé teszi, hogy a programunk futtatása közben dinamikusan alkalmazkodjunk a változó körülményekhez és ezek figyelembevétele mellett állítsuk elő a végeredményt.