8. diel - Poľa v C #
V minulej lekcii kurzu, Ošetrenie užívateľských vstupov , sme si ukázali ošetrenie užívateľských vstupov. Dnes si v C # tutoriálu predstavíme dátovú štruktúru poľa a vyskúšame si, čo všetko vie.
Poľa
Predstavte si, že si chcete uložiť nejaké údaje o viac prvkoch. Napr.
chcete v pamäti uchovávať 10 čísel, políčka šachovnice alebo mena 50tich
užívateľov. Asi vám dôjde, že v programovaní bude nejaká lepšia cesta,
než začať búšiť premenné uzivatel1
, uzivatel2
... až uzivatel50
. Nehľadiac na to, že ich môže byť
potrebné 1000. A ako by sa v tom potom hľadalo? Brrr, takze nie
Ak potrebujeme uchovávať väčšie množstvo premenných rovnakého
typu, tento problém nám rieši poľa. Môžeme si ho predstaviť ako
rad priehradiek, kde v každej máme uložený jeden prvok. Priehradky sú
očíslované tzv. Indexy, prvý má index 0
.
(Na obrázku je vidieť pole ôsmich čísiel)
Programovacie jazyky sa veľmi líšia v tom, ako s poľom pracujú. V niektorých jazykoch (najmä starších, kompilovaných) nebolo možné za behu programu vytvoriť pole s dynamickou veľkosťou (napr. Mu dať veľkosť podľa nejaké premenné). Pole sa muselo deklarovať s konštantnou veľkosťou priamo v zdrojovom kóde. Toto sa obchádzalo tzv. Pointer a vlastnými dátovými štruktúrami, čo často viedlo k chybám pri manuálnej správe pamäte a nestabilite programu (napr. V C ++ ). Naopak niektoré interpretované jazyky umožňujú nielen deklarovať pole s ľubovoľnou veľkosťou, ale dokonca túto veľkosť na už existujúcom poli meniť (napr. PHP ). My vieme, že C # je virtuálny stroj, teda čosi medzi kompilerem a interpretom. Preto môžeme pole založiť s veľkosťou, ktorú dynamicky zadáme až za behu programu, ale veľkosť existujúceho poľa modifikovať nemôžeme. Možno to samozrejme obísť alebo použiť iné dátové štruktúry, ale k tomu sa dostaneme.
Možno vás napadá, prečo sa tu zaoberáme s poľom, keď má evidentne veľa obmedzení a existujú lepšie dátové štruktúry. Odpoveď je prostá: poľa je totiž jednoduché. Nemyslím pre nás na pochopenie (to tiež), ale najmä pre C #. Rýchlo sa s ním pracuje, pretože prvky sú v pamäti jednoducho uložené za sebou, zaberajú všetky rovnako miesta a rýchlo sa k nim pristupuje. Mnoho vnútorných funkčnosťou v .NET preto nejako pracuje s poľom alebo poľa vracia. Je to kľúčová štruktúra.
Pre hromadnú manipuláciu s prvkami poľa sa používajú cykly.
Pole deklarujeme pomocou hranatých zátvoriek:
int[] pole;
Výraz pole
je samozrejme názov našej premennej. Teraz sme
však len deklarovali, že v premennej bude pole int
ov. Teraz ho
musíme založiť, aby sme ho mohli používať. Použijeme na to kľúčové
slovo new
, ktoré na našej úrovni vedomostí
nie sme zatiaľ schopní podrobne vysvetliť. Uspokojme sa s tým, že je to
kvôli tomu, že je pole referenčná dátový typ (môžeme chápať ako
zložitejšie typ):
int[] pole = new int[10];
Teraz máme v premennej pole
poľa veľkosti desiatich
int
ov.
K prvkom poľa potom pristupujeme cez hranatú zátvorku, poďme na prvý
index (teda index 0
) uložiť číslo 1
.
int[] pole = new int[10]; pole[0] = 1;
Plniť pole takhle ručne by bolo príliš pracné, použijeme cyklus a
naplníme si pole číslami od 1
do 10
. K naplneniu
použijeme for
cyklus:
int[] pole = new int[10]; pole[0] = 1; for (int i = 0; i < 10; i++) pole[i] = i + 1;
Aby sme pole vypísali, môžeme za predchádzajúci kód pripísať:
{CSHARP_CONSOLE}
int[] pole = new int[10];
pole[0] = 1;
for (int i = 0; i < 10; i++)
pole[i] = i + 1;
for (int i = 0; i < pole.Length; i++)
Console.Write("{0} ", pole[i]);
{/CSHARP_CONSOLE}
Všimnite si, že pole má vlastnosť Length
, kde je uložená
jeho dĺžka, teda počet prvkov.
Konzolová aplikácia
1 2 3 4 5 6 7 8 9 10
Môžeme použiť zjednodušenú verziu cyklu pre prácu s kolekciami, známu
ako foreach
. Ten prejde všetky prvky v poli a jeho dĺžku si
zistí sám. Jeho syntax je nasledujúca:
foreach (datovytyp premenna in kolekcia) { // príkazy }
Cyklus prejde prvky v kolekcii (to je všeobecný názov pre štruktúry, ktoré obsahujú viac prvkov, u nás to bude údaj) postupne od prvého do posledného. Prvok máme v každej iterácii cyklu uložený v danej premennej.
Prepíšme teda náš doterajší program pre foreach
. Cyklus
foreach
nemá riadiace premennú, nie je teda
vhodný pre vytvorenie nášho poľa a použijeme ho len pre výpis.
{CSHARP_CONSOLE}
int[] pole = new int[10];
pole[0] = 1;
for (int i = 0; i < 10; i++)
pole[i] = i + 1;
foreach (int i in pole)
Console.Write("{0} ", i);
Console.ReadKey();
{/CSHARP_CONSOLE}
Výstup programu:
Konzolová aplikácia
1 2 3 4 5 6 7 8 9 10
Pole samozrejme môžeme naplniť ručne a to aj bez toho, aby sme dosadzovali postupne do každého indexu. Použijeme na to zložených zátvoriek a prvky oddeľujeme čiarkou:
string[] simpsonovi = {"Homer", "Marge", "Bart", "Lisa", "Maggie"};
Pole často slúži na ukladanie medzivýsledkov, ktoré sa potom ďalej v programe používajú. Keď potrebujeme nejaký výsledok 10x, tak to nebudeme 10x počítať, ale spočítame to raz a uložíme do poľa, odtiaľ potom výsledok len načítame.
Metódy na triede Array
.NET nám poskytuje triedu Array
, ktorá obsahuje pomocné
metódy pre prácu s poľami. Poďme sa na ne pozrieť:
Sort ()
Ako už názov napovedá, metóda nám poľa zoradí. Jej jediný parameter je pole, ktoré chceme zoradiť. Je dokonca tak múdra, že pracuje podľa toho, čo máme v poli uložené. Stringy triedi podľa abecedy, čísla podľa veľkosti. Skúsme si zotrieďiť a vypísať našu rodinku Simpson:
{CSHARP_CONSOLE}
string[] simpsonovi = {"Homer", "Marge", "Bart", "Lisa", "Maggie"};
Array.Sort(simpsonovi);
foreach (string s in simpsonovi)
Console.Write("{0} ", s);
Console.ReadKey();
{/CSHARP_CONSOLE}
Konzolová aplikácia
Bart Homer Lisa Maggie Marge
Skúste si urobiť polia čísel a vyskúšajte si, že to naozaj funguje aj pre nich.
Reverse ()
Reverse()
nám pole otočí (prvý prvok bude ako posledná
atď.), Toho môžeme využiť napr. Pre triedenie pospiatky:
{CSHARP_CONSOLE}
string[] simpsonovi = {"Homer", "Marge", "Bart", "Lisa", "Maggie"};
Array.Sort(simpsonovi);
Array.Reverse(simpsonovi);
foreach (string s in simpsonovi)
Console.Write("{0} ", s);
Console.ReadKey();
{/CSHARP_CONSOLE}
IndexOf () a lastIndexOf ()
Tieto metódy vráti index prvého alebo posledného nájdeného prvku. V
prípade nenájdenia prvku vráti -1
. Každá z metód berie dva
parametre, prvým je pole, druhým hľadaný prvok. Umožníme užívateľovi
zadať meno Simpsons a povieme mu, na akej pozícii je uložený. Teraz to pre
nás nemá hlbší význam, pretože prvok poľa je len string
.
Bude sa nám to však veľmi hodiť vo chvíli, kedy v poli budeme mať
uložené plnohodnotné objekty. Berme to teda ako takú prípravu.
{CSHARP_CONSOLE}
string[] simpsonovi = {"Homer", "Marge", "Bart", "Lisa", "Maggie"};
Console.WriteLine("Ahoj zadaj svojho obľúbeného Simpsni (z rodiny Simpson): ");
string simpson = Console.ReadLine();
int pozice = Array.IndexOf(simpsonovi, simpson);
if (pozice >= 0)
Console.WriteLine("Jo, to je môj {0}. najobľúbenejší Simpson!", pozice + 1);
else
Console.WriteLine("Hele, toto nie je Simpson!");
Console.ReadKey();
{/CSHARP_CONSOLE}
Konzolová aplikácia
Ahoj zadaj svojho obľúbeného Simpsni (z rodiny Simpson):
Homer
Jo, to je môj 1. najobľúbenejší Simpson!
Copy ()
Copy()
už podľa názvu skopíruje časť poľa do iného
poľa. Prvým parametrom je zdrojové pole, druhým cieľové a tretím počet
prvkov, ktorý sa má skopírovať.
Metódy na poli
Trieda Array
nie je jedinou možnosťou, ako s poľom
manipulovať. Priamo na samotné inštanciu pole (konkrétne premenné) môžeme
volať aj veľa metód. Aj keď si spomenieme len niektoré, je ich naozaj
veľa. Nebudeme teda robiť príklady, len si ich popíšeme:
Length
Length
sme si už spomenuli, vráti dĺžku poľa. Nie je
metódou, ale vlastností, nepíšu sa za ňu teda zátvorky ()
.
Min (), Max (), Average (), Sum ()
Matematické metódy, vracajúci najmenší prvok ( Min()
),
najväčší prvok ( Max()
), priemer zo všetkých prvkov (
Average()
) a súčet všetkých prvkov ( Sum()
).
Metódy nemajú žiadne parametre.
Concat (), Intersect (), Union ()
Všetky tieto metódy vráti na výstupe nové pole a ako parameter majú
druhé pole. Concat()
vykoná nám už známu konkatenaci, teda k
nášmu poli pripojí druhé pole a takto vzniknuté nové pole vráti.
Intersect()
vykoná prienik oboch polí, teda zostaví pole s
prvkami, ktoré sú obom poliam spoločné. Union()
naopak vykoná
zjednotenie, funguje teda podobne ako Concat()
, len prvky, ktoré
boli v oboch poliach, sú v novom poli len raz.
First () a Last ()
Už podľa názvu metódy vráti prvý a posledný prvok, neberú žiadne parametre.
Take () a Skip ()
Obe tieto metódy berú ako parameter počet prvkov. Take()
vráti pole s daným počtom prvkov skopírovaných od začiatku pôvodného
poľa. Skip()
naopak vráti pole bez týchto prvých prvkov.
Contains ()
Metóda vracia true
/ false
podľa toho, či sa
prvok, uvedený v parametri metódy, v danom poli nachádzajú.
Reverse ()
Metódu Reverse()
poznáme už z triedy Array
,
pokiaľ ju ale voláme na konkrétnom poli, tak sa prvky v ňom neotočí, ale
je vytvorené nové otočené poľa a to je vrátený. Metóda nemá žiadne
parametre.
Distinct ()
Distinct()
je metóda bez parametrov a zabezpečí, aby bol v
poli každý prvok len raz, teda vymaže duplicitné prvky a unikátne pole
vráti ako návratovú hodnotu metódy, opäť teda nemodifikuje dané pole.
Mnoho metód nemení priamo naše polia, ale vráti iba polia nové (sú to
metódy Concat()
, Intersect()
, Union()
, Reverse()
a Distinct()
), v ktorom sú vykonané
požadované zmeny. Ak chceme modifikovať pôvodné pole, musíme doň
dosadiť. Tieto metódy bohužiaľ z dôvodov, ktoré pochopíme až neskôr,
nevracia priamo pole, ale typ IEnumerable
. Aby bolo dosadení
výsledku späť do poľa možné, musíme ho ešte previesť na pole metódou
ToArray()
.
int[] cisla = { 1, 2, 3, 3, 3, 5 }; cisla = cisla.Distinct().ToArray();
Premenná dĺžka poľa
Hovorili sme si, že dĺžku poľa môžeme definovať aj za behu programu, poďme si to skúsiť a rovno si vyskúšajme nejakú metódu na poli:
Console.WriteLine("Ahoj, spočítám ti priemer známok. Koľko známok zadáš?"); int pocet = int.Parse(Console.ReadLine()); int[] cisla = new int[pocet]; for (int i = 0; i < pocet; i++) { Console.Write("Zadajte {0}. číslo: ", i + 1); cisla[i] = int.Parse(Console.ReadLine()); } Console.WriteLine("Priemer tvojich známok je: {0}", cisla.Average()); Console.ReadKey();
Konzolová aplikácia
Ahoj, spočítám ti priemer známok. Koľko známok zadáš?
5
Zadajte 1. číslo: 1
Zadajte 2. číslo: 2
Zadajte 3. číslo: 2
Zadajte 4. číslo: 3
Zadajte 5. číslo: 5
Priemer tvojich známok je: 2,6
Tento príklad by išiel samozrejme napísať aj bez použitia poľa, ale čo keby sme chceli spočítať napr. Medián? Alebo napr. Vypísať zadané čísla pospiatky? To už by bez poľa nešlo. Takto máme k dispozícii v poli pôvodnej hodnoty a môžeme s nimi neobmedzene a jednoducho pracovať.
To by pre dnešok stačilo, môžete si s poľom hrať. V budúcej lekcii, Riešené úlohy k 7.-8. lekciu C # .NET , na vás čaká prekvapenie
V nasledujúcom cvičení, Riešené úlohy k 7.-8. lekciu C # .NET, si precvičíme nadobudnuté skúsenosti z predchádzajúcich lekcií.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 1423x (141.34 kB)
Aplikácia je vrátane zdrojových kódov v jazyku C#