Lekce 4 - Vícerozměrná pole v C# .NET
V minulé lekci, Spojový seznam v C#, jsme se věnovali spojovým seznamům.
Dnešní díl C# .NET tutoriálu pojednává o tzv. vícerozměrných polích.
Jednorozměrné pole
S jednorozměrným polem, které si můžeme představit jako řádku přihrádek v paměti počítače, již pracovat umíme.

(Na obrázku je vidět pole osmi čísel)
Dvourozměrné pole
Ačkoli to není tak časté, v programování se občas setkáváme i s vícerozměrnými poli, a to zejména tehdy, pokud programujeme nějakou simulaci (např. hru).
Dvourozměrné pole si můžeme v paměti představit jako tabulku. Mohli bychom takto reprezentovat např. rozehranou partii piškvorek. Pokud bychom se chtěli držet reálných aplikací, které budete později v zaměstnání tvořit, můžeme si představit, že do 2D pole budeme ukládat informace o obsazenosti sedadel v kinosále. Situaci bychom si mohli graficky znázornit např. takto:

(Na obrázku je vidět 2D pole reprezentující obsazenost kinosálu)
Kinosál by byl v praxi samozřejmě větší, ale jako ukázka nám toto
pole postačí. 0
znamená volno, 1
obsazeno. Později
bychom mohli doplnit i 2
jako rezervováno a podobně. Pro tyto
stavy by bylo správnější vytvořit si vlastní datový typ, tzv. výčet,
ale s ním se setkáme až později, proto si nyní musíme vystačit pouze s
čísly.
2D pole deklarujeme v C# .NET následujícím způsobem:
int[,] kinosal = new int [5, 5];
První číslice udává počet sloupců, druhá počet řádků (samozřejmě si to můžeme určit i obráceně, např. matice v matematice se zapisují opačně).
Všechna číselná pole v C# .NET jsou po deklaraci automaticky inicializována samými nulami, na což se můžeme spolehnout. Vytvořili jsme si tedy v paměti tabulku plnou nul.
Naplnění daty
Nyní kinosál naplníme jedničkami tak, jak je vidět na obrázku výše.
Protože budeme jako správní programátoři líní, využijeme k vytvoření
řádku jedniček for
cykly Pro přístup k prvku 2D pole musíme samozřejmě zadat dvě
souřadnice.
kinosal[2, 2] = 1; // Prostředek for (int i = 1; i < 4; i++) // 4. řádek { kinosal[i, 3] = 1; } for (int i = 0; i < 5; i++) // Poslední řádek { kinosal[i, 4] = 1; }
Výpis
Výpis pole provedeme opět pomocí cyklu, na 2D pole budeme potřebovat
cykly dva (jeden nám proiteruje sloupce a druhý řádky). Jako správní
programátoři nevložíme počet řádků a sloupců do cyklů napevno,
jelikož se údaje mohou změnit. C# .NET poskytuje na 2D poli vlastnost
Length
, jako tomu bylo u 1D pole, ale ta vrací celkový
počet prvků v poli, v našem případě tedy 25
. Nás
bude zajímat metoda GetLength()
, která jako parametr přijímá
dimenzi (0
pro sloupce, 1
pro řádky) a vrátí nám
počet prvků v této dimenzi. První dimenzí je počet sloupců, druhou počet
řádků.
Cykly zanoříme do sebe tak, aby nám vnější cyklus projížděl řádky a vnitřní sloupce v aktuálním řádku. Po výpisu řádku je nutné odřádkovat. Oba cykly musí mít samozřejmě jinou řídicí proměnnou:
{CSHARP_CONSOLE}
// deklarace
int[,] kinosal = new int [5, 5];
// naplnění daty
kinosal[2, 2] = 1; // Prostředek
for (int i = 1; i < 4; i++) // 4. řádek
{
kinosal[i, 3] = 1;
}
for (int i = 0; i < 5; i++) // Poslední řádek
{
kinosal[i, 4] = 1;
}
for (int j = 0; j < kinosal.GetLength(1); j++)
{
for (int i = 0; i < kinosal.GetLength(0); i++)
{
Console.Write(kinosal[i, j]);
}
Console.WriteLine();
}
{/CSHARP_CONSOLE}
Výsledek:
Konzolová aplikace
00000
00000
00100
01110
11111
N-rozměrná pole
Někdy může být příhodné vytvořit si pole o ještě více dimenzích. My všichni si jistě dokážeme představit minimálně 3D pole. V příkladu s kinosálem se nabízí případ užití, kdy má budova více pater (nebo obecně více kinosálů). Vizualizace by vypadala asi nějak takto:

3D pole můžeme vytvořit týmž způsobem jako 2D pole:
int[, ,] kinosaly = new int [4, 4, 3];
Kód výše vytvoří 3D pole jako na obrázku. Přistupovat k němu budeme opět přes indexer (hranaté závorky) jako předtím, jenom musíme zadat tři souřadnice:
kinosaly[3, 2, 1] = 1; // Druhý kinosál, třetí řada, čtvrtý sloupec
Pokud metodě GetLength()
zadáme parametr s hodnotou
2
, získáváme počet „pater“ (kinosálů).
Pole polí
Mnoho programovacích jazyků vícerozměrná pole nepodporuje, C# je spíše výjimkou. I v ostatních jazycích si však přesto můžeme vytvořit pole s tolika rozměry, s kolika potřebujeme, jelikož 2D pole není vnitřně nic jiného než pole polí. Situaci si můžeme představit tak, že si vytvoříme pole o pěti prvcích (první řádek) a každá buňka v tomto řádku bude v sobě obsahovat další pole, jež reprezentuje sloupeček.
Takové 2D pole deklarujeme následujícím způsobem:
int[][] kinosal = new int[5][];
Výhodou takto deklarovaného 2D pole je fakt, že si do každého řádku/sloupce můžeme uložit tak velké pole, jak chceme. V některých případech tedy nemusíme plýtvat pamětí na celou tabulku a můžeme pole vytvořit „zubaté“ (anglicky jagged):

Nevýhodou tohoto přístupu je, že musíme pole nepříjemně inicializovat sami. Původní řádek s pěti buňkami sice existuje, ale jednotlivé sloupečky si do něj musíme vložit sami (zatím si vložme všechny sloupečky o pěti prvcích):
for (int i = 0; i < kinosal.Length; i++) { kinosal[i] = new int[5]; }
C# rovněž dále neposkytuje žádný komfort ve formě získání počtu sloupců a řádků polí polí. Velikost pole musíme získat takto:
int sloupcu = kinosal.Length; int radku = 0; if (sloupcu != 0) radku = kinosal[0].Length;
Všimněme si, že je nutné ptát se na počet sloupců. Je-li totiž počet
0
, nemůžeme se dostat k prvnímu sloupci, abychom zjistili jeho
délku (počet řádků ve sloupci).
K hodnotám v poli poté přistupujeme pomocí dvou indexerů:
kinosal[4][2] = 1; // Obsazujeme sedadlo v 5. sloupci a ve 3. řadě
Použití jediného indexeru nám vrátí celý sloupeček na daném indexu.
Zkrácená inicializace vícerozměrných polí
Ještě si ukážeme, že i vícerozměrná pole je možné rovnou inicializovat hodnotami (kód vytvoří rovnou zaplněný kinosál jako na obrázku):
int[,] kinosal = new int[,] { { 0, 0, 0, 0, 1 }, { 0, 0, 0, 1, 1 }, { 0, 0, 1, 1, 1 }, { 0, 0, 0, 1, 1 }, { 0, 0, 0, 0, 1 } };
(Pole je v tomto zápisu otočené, jelikož definujeme sloupce, které zde zapisujeme jako řádky.)
Podobnou inicializaci můžeme použít dokonce i u polí zubatých (kód níže vytvoří zubaté pole jako na obrázku):
int[][] zubatePole = new int[][] { new int[] {15, 2, 8, 5, 3}, new int[] {3, 3, 7}, new int[] {9, 1, 16, 13}, new int[] {}, new int[] {5} };
Na závěr bychom rádi dodali, že někteří lidé, kteří neumějí
správně používat objekty, využívají 2D pole k ukládání více údajů o
jediné entitě. Např. budeme chtít uložit výšku, šířku a délku pěti
mobilních telefonů. Ačkoli se vám nyní může zdát, že se jedná o úlohu
pro 3D pole, ve skutečnosti se jedná o úlohu pro obyčejné 1D pole
(přesněji seznam) objektů typu Telefon
. Pole si určitě ještě
vyzkoušejte ve cvičení v tomto kurzu.
V následujícím kvízu, Kvíz - Genericita, List, N-rozměrné pole v C# .NET Kolekce, si vyzkoušíme nabyté zkušenosti z předchozích lekcí.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 463x (32.73 kB)
Aplikace je včetně zdrojových kódů v jazyce C#