15. fejezet - Listák feltöltésével kapcsolatos feladatok (szerző: Hernyák zoltán)

Tartalom

A fejezet forráskódjai

Az alábbi feladatokban egyszerű, C# alaptípusból alkotott listákkal, majd rekordokat tartalmazó listák feltöltésével kapcsolatos feladatokkal foglalkozunk.

15.1. feladat (Feltöltés billentyűzetről N elemszámraszint: 1). Egy törtszámokat tartalmazó listát töltsünk fel billentyűzetről oly módon, hogy a program kezelője a program elején megadja, hogy hány elemre lehet számítani(n), majd beírja az n számú törtértéket! A program a bevitel közben mindig írja ki, hogy hányadik számnál tart a bevitel, és mennyi van még hátra! A program a bevitel végén írja vissza az adatokat a képernyőre, a számokat egymás mellé írva, szóközzel elválasztva, majd adja meg a számok átlagát!

Magyarázat: A feladat egy egyszerű ciklussal megoldható, lényegében problémamentes. Ha valaki jobb minőségű kódot szeretne készíteni, legfeljebb arra kell ügyelnie, hogy a beírt szám valóban tört alakú legyen. Tudni kell, hogy magyar területi beállítások mellett a Double.Parse a törtszámokban a tizedesvessző megjelenésére számít, és nem a tizedespontra. A bekérésben esetleg előforduló tizedespontot vesszőre tudjuk cserélni a Replace metódus hívásával (a 15.1. forráskód).

15.2. feladat (Feltöltés billentyűzetről szám végjeligszint: 1). Egy törtszámokat tartalmazó listát töltsünk fel billentyűzetről oly módon, hogy a program kezelője a program elején nem adja meg, hogy hány adat lesz! Helyette választunk egy speciális számértéket, például a 0.0 értéket. Amennyiben ezt a számot írnánk be, úgy a program fejezze be a bevitelt! A program a bevitel végén írja vissza az adatokat a képernyőre, a számokat egymás mellé írva, szóközzel elválasztva, majd adja meg a számok átlagát!

Magyarázat: A vége jel kezelése egy középen tesztelős ciklussal a leglátványosabb, legegyszerűbb. Ismert tény, hogy sokan ódzkodnak a középen tesztelős ciklustól, a break használatától. Megpróbálhatjuk megírni ezt a ciklust is akár elöl tesztelős, akár hátul tesztelős tisztán logikai ciklussal, amelyben nincs break, de azt fogjuk találni, hogy a kilépési tesztet x==0.0 kétszer is be kell írnunk. Ekkor pedig kitörhet a lázadás a kódredundancia oldaláról. Nem törünk lándzsát egyik megoldás mellett sem, és ellene sem foglalunk állást (egyfajta megoldást lásd a 15.2. forráskódban).

15.3. feladat (Feltöltés billentyűzetről string végjeligszint: 1). Egy törtszámokat tartalmazó listát töltsünk fel billentyűzetről oly módon, hogy a program kezelője a számok bevitelét egy speciális szöveggel zárja (pl. a „*” karaktert írja be, vagy begépeli, hogy „vége”)! A program a bevitel végén írja vissza az adatokat a képernyőre, a számokat egymás mellé írva, szóközzel elválasztva, majd adja meg a számok átlagát!

Magyarázat: Az előző feladat megoldása után ez sem jelenthet gondot, mindössze arra kell ügyelni, hogy a vége ellenőrzést a double.Parse előtt hajtsuk végre, mivel a különleges stringértékek nem parzolhatóak át számmá, kivétel dobásával leállna a program (lásd a 15.3. forráskód).

15.4. feladat (Feltöltés véletlen számokkalszint: 1). Egy listát töltsünk fel véletlen egész számokkal oly módon, hogy a páros sorszámú listaelemek a , a páratlan sorszámú listaelemek a intervallumból kerüljenek ki! A listába kerüljön be n ilyen szám, az n értékét a program induláskor kérje be! A program a végén írja vissza az adatokat a képernyőre, a számokat egymás mellé írva, vesszővel elválasztva, majd adja meg a számok átlagát!

Magyarázat: Gyakori elvi hiba kezdő programozóknál, hogy nem egy, de több Random példányt is készítenek programjaikban. Tudnunk kell, hogy a Random példányok a véletlenszám-generáláshoz szükséges kezdőértéket a rendszerórából veszik át. Ezért a közel egy időben készült példányok egy kezdőértékről indulnak, ugyanazon véletlen számokat fogják előállítani (természetesen ha ugyanazon intervallumot használjuk). Különböző intervallumok használata sem indokolja a több Random példány jelenlétét a programban, mivel minden egyes véletlenszám-előállítás esetén külön-külön kell megadni a kívánt intervallumot. Ezért is egyetlen Random példányt érdemes használni végig a generálás során (15.4. forráskód).

Másrészről ügyelnünk kell az átlagszámításra, mivel itt már nem törtszámok, de egész számok átlagáról van szó. Ekkor a korábban használt sum/n nem fog helyes eredményt adni, ha a sum típusa (és az n típusa is) egész szám. Nem érdemes sem a sum, sem az n típusát másra választani, helyette explicit típuskonverziót kell használni az osztás elvégzésekor (double)sum/n (lásd 15.5. forráskód).

15.5. feladat (Feltöltés véletlen növekvő számokkalszint: 1). Egy listát töltsünk fel véletlen egész számokkal oly módon, hogy az első listaelem a intervallumba essen, a következő listalemek az őket megelőző elemtől legyenek „valamennyivel” nagyobbak, a különbség az intervallumból kerüljön ki! A lista hosszát (n darab) a program induláskor kérje be! A program a végén írja vissza az adatokat a képernyőre, a számokat egymás mellé írva, vesszővel elválasztva, majd adja meg a számok átlagát!

Magyarázat: A lista első elemét megadott módon kell képezni. A következő elem értékének előállításához az előző értékből kell kiindulni, melyhez újabb random értéket kell adni. A feladat nem túl bonyolult, de eredménye nagyon értékes. Anélkül kaphatunk „rendezett”, véletlen számokat tartalmazó számsort, hogy rendezőalgoritmust kellene ismernünk! A megoldást lásd a 15.6. forráskódban.

15.6. feladat (Feltöltés fájlból (a)szint: 1). Egy text fájl soronként egy törtszámot tartalmaz. Írjunk olyan programot, amely bekéri a fájl nevét, majd beolvassa a számokat a fájlból! A bevitel véget ér, ha a fájl minden sorát beolvastuk, vagy üres sort olvastunk be a fájlból. A program a bevitel végén írja vissza az adatokat a képernyőre, a számokat egymás mellé írva, vesszővel elválasztva, majd adja meg a számok átlagát!

Magyarázat: A fájlból beolvasást többször bemutattuk már. Mivel ennek során stringeket olvasunk be, az üres sor detektálása sem lehet problémás. Az üres sor felfedezéséhez egy jó minőségű megoldást mutatunk be a 15.7. forráskódban. Alkalmazzuk a beolvasott sorra a Trim függvényt (ez levágja a sor bevezető és záró white-space karaktereit), a kapott string hosszát vessük össze a 0-val!

15.7. feladat (Feltöltés fájlból (b)szint: 1). Egy text fájl soronként egy vagy több törtszámot tartalmaz. Amikor több szám is szerepel egy sorban, akkor vesszővel vannak elválasztva. A vessző után szóközök is szerepelhetnek a jobb vizuális tördelés érdekében. Írjunk olyan programot, amely bekéri a fájl nevét, majd beolvassa a számokat a fájlból! A bevitel véget ér, ha a fájl minden sorát beolvastuk, vagy üres sort olvastunk be a fájlból. A program a bevitel végén írja vissza az adatokat a képernyőre, a számokat egymás mellé írva, vesszővel elválasztva, majd adja meg a számok átlagát!

Magyarázat: A beolvasott értékes sort a Split függvény segítségével vághatjuk fel a vessző karakter mentén törtszámokra. A darabokra alkalmazzuk a Trim függvényt, hogy a feladatban is említett felesleges szóközöket levágjuk. A kapott számokat adjuk hozzá a listához (15.8. forráskód)!

15.8. feladat (Feltöltés billentyűzetről listaszerűenszint: 1). Egy egész számokat tartalmazó listát töltsünk fel billentyűzetről oly módon, hogy a program kezelője egy időben egyszerre több számot is beírhat, vesszővel elválasztva! Ekkor minden számot adjunk hozzá a listához! Ha csak egy számot írna be a kezelő, akkor azt az egy számot. A bevitelt akkor fejezzük be, ha a kezelő egyetlen számot sem ír be (üres string)! A program a bevitel végén írja vissza az adatokat a képernyőre, a számokat egymás mellé írva, vesszővel elválasztva, majd adja meg a számok átlagát!

Magyarázat: Az előző feladatban ismertetett módszer tökéletesen alkalmas ebben a feladatban is, csak a sor beolvasását ez esetben nem a fájlból, hanem billentyűzetről kell elvégezni (15.9. forráskód).

15.9. feladat (Feltöltés billentyűzetről összeghatárigszint: 1). Egy egész számokat tartalmazó listát töltsünk fel billentyűzetről oly módon, hogy a program kezelője addig írhat be számokat, amíg azok összege el nem éri az előre megadott értéket (például 100)! A program a bevitel közben folyamatosan figyelje az összeghatárt, illetve mindig írja ki, hogy hányadik számnál tart a bevitel, hol tart az összeg, mennyi van még hátra az értékhatárig! A program a bevitel végén írja vissza az adatokat a képernyőre, a számokat egymás mellé írva, vesszővel elválasztva, majd adja meg a számok átlagát!

Magyarázat: A korábban ismertetett adatbekéréseket alapul vehetjük, mindössze a kilépés feltétele változik meg ez esetben (15.10. forráskód).

15.10. feladat (Feltöltés egyedi számokkalszint: 1). Egy egész számokat tartalmazó listát töltsünk fel billentyűzetről oly módon, hogy a listába nem kerülhet be ugyanazon szám többször is! Ha a program kezelője olyan számot írna be, amely már volt, akkor a program ezt jelezze ki! A bevitelt a kezelő akkor fejezheti be, ha sikerült neki egymás után háromszor is olyan értéket beírni, amely még nem szerepelt korábban (amit a program elfogad). A program a bevitel végén írja vissza az adatokat a képernyőre, a számokat egymás mellé írva, vesszővel elválasztva, majd adja meg a számok átlagát!

Magyarázat: Olvassuk el figyelmesen a feladatot! Nem akkor kell befejezni az adatbevitelt, amikor a lista mérete eléri a 3-at (3 különböző számot tartalmaz), hanem amikor egymás után 3-szor sikeres adatbevitel történt. Érdemes bevezetni egy sikeres számlálót, melyet minden siker esetén növelünk 1-gyel, ha hibázunk, akkor lenullázzuk. A bevitel akkor fejeződik be, amikor a számláló eléri a 3-at.

A sikeresség ellenőrzéséhez érdemes kifejleszteni egy egyszerű függvényt, mely megadja a lista aktuális tartalma és egy új x érték esetén, hogy ez az x érték szerepel-e a listán vagy sem (15.11. forráskód). Ez alapján a főprogram már könnyen kialakítható (15.12. forráskód).

15.11. feladat (Fájlból két halmazszint: 2). Egy text fájl soronként egy vagy több törtszámot tartalmaz. Amikor több szám is szerepel egy sorban, akkor vesszővel vannak elválasztva. A vessző után szóközök is szerepelhetnek a jobb vizuális tördelés érdekében. A text fájl két számlistát tartalmaz, a két számlista között egy üres sor szerepel a fájlban. A program olvassa be mindkét számlistát két különböző listaváltozóba! Adjuk meg, melyik számlistában szereplő számoknak nagyobb az átlaga!

Magyarázat: A 15.7. feladat megoldása során bemutatott módszer alapján a feladat már szinte problémamentesen megoldható. Az üres sor első elérésekor nem kell leállni a beolvasáskor, hanem folytatni kell a második üres sor vagy a fájl végének eléréséig.

Trükkös megoldást alkalmazhatunk, ha jól uraljuk a referencia típust. Egy harmadik lista változót vezethetünk be, mely először az első listára mutat, majd váltáskor a második listára állunk át vele. Számoljuk az üres sorok számát is, de csak akkor lépünk ki a ciklusból, ha ez a számláló eléri a 2-t. A megoldást lásd a 15.13. forráskódban.

A fejezet forráskódjai

15.1. forráskód. Lista feltöltése billentyűzetről

     
List<double> szamok = new List<double>(); 
Console.Write("Hany szamrol lesz szo:"); 
int n = int.Parse(Console.ReadLine()); 
for (int i = 0; i < n; i++) 
{ 
   Console.Write("Kerem a {0}. szamot:", i + 1); 
   string s = Console.ReadLine(); 
   double d = double.Parse( s.Replace(’.’,’,’)); 
   szamok.Add(d); 
} 
// 
foreach (double x in szamok) 
   Console.Write("{0} ", x); 
Console.WriteLine(); 
// 
double sum = 0; 
foreach (double x in szamok) 
   sum = sum+x; 
Console.WriteLine("Atlag={0}", sum / n);
    

15.2. forráskód. Lista feltöltése végjelig

 
List<double> szamok = new List<double>(); 
int i = 0; 
while (true) 
{ 
   Console.Write("Kerem a {0}. szamot:", i + 1); 
   string s = Console.ReadLine(); 
   double d = double.Parse( s.Replace(’.’,’,’)); 
   if (d == 0.0) break; 
   else szamok.Add(d); 
   i++; 
}
                                                                                                                                     

                                                                                                                                     
    

15.3. forráskód. Lista feltöltése string végjelig

 
List<double> szamok = new List<double>(); 
int i = 0; 
while (true) 
{ 
   Console.Write("Kerem a {0}. szamot:", i + 1); 
   string s = Console.ReadLine(); 
   if (s == "*" || s == "vege") break; 
   double d = double.Parse( s.Replace(’.’,’,’)); 
   szamok.Add(d); 
   i++; 
}

15.4. forráskód. Lista generálása

 
List<double> szamok = new List<double>(); 
Random rnd = new Random(); 
for(int i=0;i<n;i++) 
{ 
   if (i % 2 == 0) szamok.Add(rnd.Next(10, 51)); 
   else szamok.Add(rnd.Next(40, 81)); 
}

15.5. forráskód. Egész számok átlaga

 
int sum = 0; 
foreach (int x in szamok) 
   sum = sum+x; 
Console.WriteLine("Atlag={0}", (double) sum / n);

15.6. forráskód. Rendezett lista generálása

 
List<int> szamok = new List<int>(); 
Random rnd = new Random(); 
int x = rnd.Next(10, 31); 
for(int i=0;i<n;i++) 
{ 
   szamok.Add(x); 
   x = x + rnd.Next(1, 6); 
}

15.7. forráskód. Lista feltöltése számokkal file-ból

     
List<double> szamok = new List<double>(); 
StreamReader f = new StreamReader(@"szamok.txt", Encoding.Default); 
while (f.EndOfStream == false) 
{ 
   string s = f.ReadLine(); 
   if (s.Trim().Length==0) break; 
   double d = double.Parse( s.Replace(’.’,’,’) ); 
   szamok.Add( d ); 
} 
f.Close();
    

15.8. forráskód. A fájlban egy sorban több szám is szerepelhet

 
List<double> szamok = new List<double>(); 
StreamReader f = new StreamReader(@"szamok.txt", Encoding.Default); 
while (f.EndOfStream == false) 
{ 
   string s = f.ReadLine(); 
   if (s.Trim().Length==0) break; 
   string[] ss = s.Split(’,’); 
   foreach(string p in ss) 
   { 
      double d = double.Parse( p.Trim().Replace(’.’,’,’)); 
      szamok.Add( d ); 
   } 
} 
f.Close();

15.9. forráskód. A beírt sorban több szám is szerepelhet

 
List<int> szamok = new List<int>(); 
while (true) 
{ 
   string s = Console.ReadLine(); 
   if (s.Trim().Length==0) break; 
   string[] ss = s.Split(’,’); 
   foreach(string p in ss) 
   { 
      int d = int.Parse(p.Trim()); 
      szamok.Add( d ); 
   } 
}

15.10. forráskód. Adatbekérés összeghatárig

 
List<int> szamok = new List<int>(); 
int sum = 0; 
while (sum<100) 
{ 
   string s = Console.ReadLine(); 
   if (s.Trim().Length==0) break; 
   int d = int.Parse(s.Trim()); 
   szamok.Add( d ); 
   sum = sum + d; 
}

15.11. forráskód. Ellenőrző függvény: az x szerepel-e a listán

 
static bool szerepel_e(List<int> l, int x) 
{ 
   foreach (int d in l) 
      if (d == x) return true; 
   // 
   return false; 
}
                                                                                                                                     

                                                                                                                                     
    

15.12. forráskód. Az adatbekérés főprogramja

 
List<int> szamok = new List<int>(); 
int siker = 0; 
while (siker<3) 
{ 
   string s = Console.ReadLine(); 
   int d = int.Parse(s.Trim()); 
   if (szerepel_e(szamok, d) == true) siker = 0; 
   else 
   { 
      szamok.Add(d); 
      siker++; 
   } 
}

15.13. forráskód. Két számhalmaz beolvasása

 
List<double> szamok1 = new List<double>(); 
List<double> szamok2 = new List<double>(); 
List<double> akt = szamok1; 
StreamReader f = new StreamReader(@"szamok.txt", Encoding.Default); 
int ures_db = 0; 
while (f.EndOfStream == false) 
{ 
   string s = f.ReadLine(); 
   if (s.Trim().Length == 0) 
   { 
      ures_db++; 
      if (ures_db == 2) break; 
      akt = szamok2; 
      continue; 
   } 
   string[] ss = s.Split(’,’); 
   foreach (string p in ss) 
   { 
      double d = double.Parse(p.Trim().Replace(’.’, ’,’)); 
      akt.Add(d); 
   } 
} 
f.Close();