Lekce 8 - Pole ve VB.NET
V minulé lekci, Ošetření uživatelských vstupů ve VB.NET, jsme si ukázali ošetření uživatelských vstupů.
V dnešním VB.NET tutoriálu si představíme datovou strukturu pole a vyzkoušíme si, co všechno umí.
Pole
Představte si, že si chcete uložit nějaké údaje o více prvcích.
Např. chcete v paměti uchovávat 10 čísel, políčka šachovnice nebo jména
50ti uživatelů. Asi vám dojde, že v programování bude nějaká lepší
cesta, než začít bušit proměnné uzivatel1
,
uzivatel2
, ... až uzivatel50
. Nehledě
na to, že jich může být třeba 1000. A jak by se v tom potom hledalo? Brrr,
takhle ne
Pokud potřebujeme uchovávat větší množství proměnných
stejného typu, tento problém nám řeší pole. Můžeme si ho
představit jako řadu přihrádek, kde v každé máme uložený jeden prvek.
Přihrádky jsou očíslované tzv. indexy, první má index 0
.
(Na obrázku je vidět pole osmi čísel)
Programovací jazyky se velmi liší v tom, jak s polem pracují. V některých jazycích (zejména starších, kompilovaných) nebylo možné za běhu programu vytvořit pole s dynamickou velikostí (např. mu dát velikost dle nějaké proměnné). Pole se muselo deklarovat s konstantní velikostí přímo ve zdrojovém kódu. Toto se obcházelo tzv. pointery a vlastními datovými strukturami, což často vedlo k chybám při manuální správě paměti a nestabilitě programu (např. v C++). Naopak některé interpretované jazyky umožňují nejen deklarovat pole s libovolnou velikostí, ale dokonce tuto velikost na již existujícím poli měnit (např. PHP). My víme, že VB.NET je virtuální stroj, tedy cosi mezi kompilerem a interpretem. Proto můžeme pole založit s velikostí, kterou dynamicky zadáme až za běhu programu, ale velikost existujícího pole modifikovat nemůžeme. Lze to samozřejmě obejít nebo použít jiné datové struktury, ale k tomu se dostaneme.
Možná vás napadá, proč se tu zabýváme s polem, když má evidentně mnoho omezení a existují lepší datové struktury. Odpověď je prostá: pole je totiž jednoduché. Nemyslím pro nás na pochopení (to také), ale zejména pro Visual Basic. Rychle se s ním pracuje, protože prvky jsou v paměti jednoduše uloženy za sebou, zabírají všechny stejně místa a rychle se k nim přistupuje. Mnoho vnitřních funkčností v .NET proto nějak pracuje s polem nebo pole vrací. Je to klíčová struktura.
Pro hromadnou manipulaci s prvky pole se používají cykly.
Pole deklarujeme pomocí kulatých závorek:
Dim pole(9) As Integer
Slovo pole
je samozřejmě název naší proměnné. Nyní jsme
deklarovali, že v proměnné bude pole 10 prvků typu Integer
.
Pole se založí automaticky, pokud zadáme počet prvků v poli. Nyní máme v
proměnné pole
pole o velikosti 10 čísel typu
Integer
. Pozor na skutečnost, že jako délku zadáváme
poslední index, který je číslovaný od nuly, pole(9)
má tedy
10
prvků.
K prvkům pole potom přistupujeme přes kulatou závorku, pojďme na první
index (tedy index 0
) uložit číslo 1
.
Dim pole(9) As Integer pole(0) = 1
Plnit pole takhle ručně by bylo příliš pracné, použijeme cyklus a
naplníme si pole čísly od 1
do 10
. K naplnění
použijeme For
cyklus:
Dim pole(9) As Integer For i As Integer = 0 To 9 pole(i) = i + 1 Next
Abychom pole vypsali, můžeme za předchozí kód připsat:
{VBNET_CONSOLE}
Dim pole(9) As Integer
For i As Integer = 0 To 9
pole(i) = i + 1
Next
For i As Integer = 0 To pole.Length - 1
Console.Write("{0} ", pole(i))
Next
{/VBNET_CONSOLE}
Všimněte si, že pole má vlastnost Length
, kde je uložena
jeho délka, tedy počet prvků.
Konzolová aplikace
1 2 3 4 5 6 7 8 9 10
Můžeme použít zjednodušenou verzi cyklu pro práci s kolekcemi, známou
jako For Each
. Ten projede všechny prvky v poli a jeho délku si
zjistí sám. Jeho syntaxe je následující:
For Each promenna As Integer In pole Console.WriteLine(promenna) Next
Cyklus projede prvky v kolekci (to je obecný název pro struktury, které obsahují více prvků, u nás to bude pole) postupně od prvního do posledního. Prvek máme v každé iteraci cyklu uložený v dané proměnné.
Přepišme tedy náš dosavadní program pro For Each
.
For Each
nemá řídící proměnnou, není tedy
vhodný pro vytvoření našeho pole a použijeme ho jen pro výpis.
{VBNET_CONSOLE}
Dim pole(9) As Integer
pole(0) = 1
For i As Integer = 0 To 9
pole(i) = i + 1
Next
For Each promenna As Integer In pole
Console.Write("{0} ", promenna)
Next
Console.ReadKey()
{/VBNET_CONSOLE}
Výstup programu:
Konzolová aplikace
1 2 3 4 5 6 7 8 9 10
Pole samozřejmě můžeme naplnit ručně a to i bez toho, abychom dosazovali postupně do každého indexu. Použijeme k tomu složených závorek a prvky oddělujeme čárkou:
Dim simpsonovi() = {"Homer", "Marge", "Bart", "Lisa", "Maggie"}
Všimněte si, že v tomto případě jsme nemuseli uvést počet prvků.
Pole často slouží k ukládání mezivýsledků, které se potom dále v programu používají. Když něco potřebujeme 10x, tak to nebudeme 10x počítat, ale spočítáme to jednou a uložíme do pole, odtud poté výsledek jen načteme.
Metody na třídě Array
.NET nám poskytuje třídu Array
, která obsahuje pomocné
metody pro práci s poli. Pojďme se na ně podívat:
Sort()
Jak již název napovídá, metoda nám pole seřadí. Její jediný parametr
je pole, které chceme seřadit. Je dokonce tak chytrá, že pracuje podle toho,
co máme v poli uložené. Stringy
třídí podle abecedy, čísla
podle velikosti. Zkusme si seřadí a vypsat naši rodinku Simpsnů:
{VBNET_CONSOLE}
Dim simpsonovi() = {"Homer", "Marge", "Bart", "Lisa", "Maggie"}
Array.Sort(simpsonovi)
For Each s As String In simpsonovi
Console.Write("{0} ", s)
Next
Console.ReadKey()
{/VBNET_CONSOLE}
Konzolová aplikace
Bart Homer Lisa Maggie Marge
Zkuste si udělat pole čísel a vyzkoušejte si, že to opravdu funguje i pro ně.
Reverse()
Reverse()
nám pole otočí (první prvek bude jako poslední
atd.), toho můžeme využít např. pro třídění pozpátku:
{VBNET_CONSOLE}
Dim simpsonovi() = {"Homer", "Marge", "Bart", "Lisa", "Maggie"}
Array.Sort(simpsonovi)
Array.Reverse(simpsonovi)
For Each s As String In simpsonovi
Console.Write("{0} ", s)
Next
Console.ReadKey()
{/VBNET_CONSOLE}
IndexOf()
a
LastIndexOf()
Tyto metody vrátí index prvního nebo posledního nalezeného prvku. V
případě nenalezení prvku vrátí -1
. Metoda bere dva parametry,
prvním je pole, druhým hledaný prvek. Umožníme uživateli zadat jméno
Simpsna a řekneme mu, na jaké pozici je uložený. Teď to pro nás nemá
hlubší význam, protože prvek pole je jen String
. Bude se nám
to však velmi hodit ve chvíli, kdy v poli budeme mít uloženy plnohodnotné
objekty. Berme to tedy jako takovou přípravu.
{VBNET_CONSOLE}
Dim simpsonovi() = {"Homer", "Marge", "Bart", "Lisa", "Maggie"}
Console.WriteLine("Ahoj, zadej svého oblíbeného Simpsna (z rodiny Simpsnů): ")
Dim simpson As String = Console.ReadLine()
Dim pozice As Integer = Array.IndexOf(simpsonovi, simpson)
If pozice >= 0 Then
Console.WriteLine("Jo, to je můj {0}. nejoblíbenější Simpson!", pozice + 1)
Else
Console.WriteLine("Hele, tohle není Simpson")
End If
Console.ReadKey()
{/VBNET_CONSOLE}
Konzolová aplikace
Ahoj, zadej svého oblíbeného Simpsna (z rodiny Simpsů):
Homer
Jo, to je můj 1. nejoblíbenější Simpson!
Copy()
Copy()
již podle názvu zkopíruje část pole do jiného pole.
Prvním parametrem je zdrojové pole, druhým cílové a třetím počet znaků,
který se má zkopírovat.
Metody na poli
Třída Array
není jedinou možností, jak s polem manipulovat.
Přímo na samotné instanci pole (konkrétní proměnné) můžeme volat také
spoustu metod. I když si zmíníme jen některé, je jich opravdu hodně.
Nebudeme tedy dělat příklady, jen si je popíšeme:
Length
Length
jsme si již zmínili, vrátí délku pole. Není
metodou, ale vlastností, nepíší se za ni tedy závorky ()
.
Min()
, Max()
,
Average()
, Sum()
Matematické metody, vracející nejmenší prvek (Min()
),
největší prvek (Max()
), průměr ze všech prvků
(Average()
) a součet všech prvků (Sum()
). Metody
nemají žádné parametry.
Concat()
,
Intersect()
, Union()
Všechny tyto metody vrátí na výstupu nové pole a jako parametr mají
druhé pole. Concat()
vykoná nám již známou konkatenaci, tedy k
našemu poli připojí druhé pole a takto vzniklé nové pole vrátí.
Intersect()
vykoná průnik obou polí, tedy sestaví pole s prvky,
které jsou oběma polím společné. Union()
naopak vykoná
sjednocení, funguje tedy podobně jako Concat()
, jen prvky, které
byly v obou polích, jsou v novém poli jen jednou.
First()
a Last()
Již podle názvu metody vrátí první a poslední prvek, neberou žádné parametry.
Take()
a Skip()
Obě tyto metody berou jako parametr počet prvků. Take vrátí pole s
daným počtem prvků zkopírovaných od začátku původního pole.
Skip()
naopak vrátí pole bez těchto prvních prvků.
Contains()
Metoda vrací True
/False
podle toho, zda se prvek,
uvedený v parametru metody, v daném poli nachází.
Reverse()
Metodu Reverse()
známe již z třídy Array
, pokud
ji ale voláme na konkrétním poli, tak se prvky v něm neotočí, nýbrž je
vytvořeno nové otočené pole a to je vráceno. Metoda nemá žádné
parametry.
Distinct()
Distinct()
je metoda bez parametrů a zajistí, aby byl v poli
každý prvek jen jednou, tedy vymaže duplicitní prvky a unikátní pole
vrátí jako návratovou hodnotu metody, opět tedy nemodifikuje dané pole.
Mnoho metod nemění přímo naše pole, ale vrátí pouze pole nové (jsou
to metody Concat()
, Intersect()
, Union()
,
Reverse()
a Distinct()
), ve kterém jsou provedeny
požadované změny. Pokud chceme modifikovat původní pole, musíme do něj
takto dosadit. Tyto metody bohužel z důvodů, které pochopíme až později,
nevrací přímo pole, ale typ IEnumerable
. Aby bylo dosazení
výsledku zpět do pole možné, musíme ho ještě převést na pole metodou
ToArray()
.
Dim cisla() = { 1, 2, 3, 3, 3, 5 } cisla = cisla.Distinct().ToArray()
Proměnná délka pole
Říkali jsme si, že délku pole můžeme definovat i za běhu programu, pojďme si to zkusit a rovnou si vyzkoušejme nějakou metodu na poli:
Console.WriteLine("Ahoj, spočítám ti průměr známek. Kolik známek zadáš?") Dim pocet As Integer = Console.ReadLine() Dim cisla(pocet - 1) As Integer For i As Integer = 0 To pocet - 1 Console.Write("Zadejte {0}. číslo: ", i + 1) cisla(i) = Console.ReadLine() Next Console.WriteLine("Průměr tvých známek je: {0}", cisla.Average()) Console.ReadKey()
Konzolová aplikace
Ahoj, spočítám ti průměr známek. Kolik známek zadáš?
5
Zadejte 1. číslo: 1
Zadejte 2. číslo: 2
Zadejte 3. číslo: 2
Zadejte 4. číslo: 3
Zadejte 5. číslo: 5
Průměr tvých známek je: 2,6
Tento příklad by šel samozřejmě napsat i bez použití pole, ale co kdybychom chtěli spočítat např. medián? Nebo např. vypsat zadaná čísla pozpátku? To už by bez pole nešlo. Takhle máme k dispozici v poli původní hodnoty a můžeme s nimi neomezeně a jednoduše pracovat.
To by pro dnešek stačilo, můžete si s polem hrát.
V následujícím kvízu, Kvíz - Podmínky, cykly a pole ve VB.NET, si vyzkoušíme nabyté zkušenosti z předchozích lekcí.