NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!
NOVINKA - Online rekvalifikační kurz Java programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.

Lekce 7 - Pole ve Swift

V minulé lekci kurzu, Typový systém: Optionals ve Swift, jsme se naučili používat Optionals.

Dnes si ve Swift tutoriálu 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 50 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.

Struktura pole ve Swift - Základní konstrukce jazyka Swift

(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). Swift k polím přistupuje poměrně moderně. Neřeší velikost (ani ji nemůžete pevně zadat) a pro přidávání prvků se používá metoda, takže nemusíte řešit indexy. Tomuto typu kolekce (kontejnerové struktury) se v některých jazycích říká spíše seznam, než pole. Swift jej ovšem jako pole označuje. Pro hromadnou manipulaci s prvky pole se používají cykly.

Pole deklarujeme pomocí hranatých závorek a obyčejných závorek:

var pole = [Int]()

Výraz pole je samozřejmě název naší proměnné.

K prvkům pole potom přistupujeme přes hranatou závorku, ale pouze, pokud již tento prvek existuje. To může být matoucí, pokud přicházíte z jiného jazyka. Prvky nejdříve přidáme metodou append(), které můžeme v našem případě předat číslo (Int, který se uloží na konec pole) nebo klidně další pole stejného typu (tedy typu Int v našem případě).

var pole = [Int]()
pole.append(34)

Plnit pole takto 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:

var pole = [Int]()
for i in 1...10 {
    pole.append(i)
}

Abychom pole vypsali, můžeme za předchozí kód připsat:

for cislo in pole {
    print(cislo, terminator:" ")
}

Nyní už je lépe vidět síla jiného zápisu for cyklu ve Swiftu. Ostatní jazyky mívají další foreach, nám ale stačí za in místo definované řady čísel vložit pole a cyklus projde všechny prvky, ke kterým se v jeho těle můžeme dostat.

1 2 3 4 5 6 7 8 9 10

Pole má vlastnost count, kde je uložen počet prvků.

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 hranatých závorek a prvky oddělujeme čárkou:

let simpsonovi = ["Homer", "Marge", "Bart", "Lisa", "Maggie"]

Protože nechceme, aby nám někdo obsah pole měnil, deklarujeme ho pomocí let a tím se pole stává konstantní. Vynechali jsme upřesnění typu, protože Swift snadno pozná, že jde o pole stringů. Samozřejmě nám ale nic nebrání ho doplnit:

let simpsonovi : [String] = ["Homer", "Marge", "Bart", "Lisa", "Maggie"]

Pole často slouží k ukládání mezivýsledků, které se potom dále v programu používají. Když potřebujeme nějaký výsledek 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 dostupné pro pole

Swift nám poskytuje pomocné metody pro práci s poli. Pojďme se na ně podívat:

sort() a sorted()

Jak již název napovídá, metody nám pole seřadí. Metoda sort() setřídí existující pole (takže musí být deklarované s var) a sorted() nám vrátí nové setříděné pole, takže ho nesmíte zapomenout přiřadit do proměnné. Metody jsou dokonce tak chytré, že pracují podle toho, co máme v poli uložené. Hodnoty typu String se třídí podle abecedy, čísla podle velikosti. Zkusme si setřídit a vypsat naši rodinku Simpsnů:

var simpsonovi = ["Homer", "Marge", "Bart", "Lisa", "Maggie"]
simpsonovi.sort()
for simpson in simpsonovi {
    print(simpson)
}

Výstup:

Bart
Homer
Lisa
Maggie
Marge

A způsob seřazení pomocí metody sorted():

var simpsonovi = ["Homer", "Marge", "Bart", "Lisa", "Maggie"]

let simpsonovi_sorted = simpsonovi.sorted()
for simpson in simpsonovi_sorted {
    print(simpson)
}

Výstup:

Bart
Homer
Lisa
Maggie
Marge

Zkuste si udělat pole čísel a vyzkoušejte si, že to opravdu funguje i pro ně.

reverse() a reversed()

Tyto metody nám pole otočí (první prvek bude jako poslední atd.). Princip je opět stejný jako u třídění. Metoda reverse() setřídí existující pole, reversed() nám potom seřazené pole vrátí. Toho můžeme využít např. pro třídění pozpátku:

var simpsonovi = ["Homer", "Marge", "Bart", "Lisa", "Maggie"]
simpsonovi.sort()
simpsonovi.reverse()
for simpson in simpsonovi {
    print(simpson)
}

Výstup:

Marge
Maggie
Lisa
Homer
Bart

index(of: )

Vrací index daného prvku. Metoda nám vrátí Optional(Int), protože se může stát, že prvek v poli prostě neexistuje a v takovém případě nemá smysl vracet jakoukoliv hodnotu. Optionals byste měli znát z předchozí lekce. Abychom se k možné hodnotě dostali bezpečně, použijeme konstrukci if let, která do proměnné pozice přiřadí hodnotu indexu Simpsna, pokud takový v našem poli existuje. Jestliže neexistuje, tak se provede else větev.

let simpsonovi = ["Homer", "Marge", "Bart", "Lisa", "Maggie"]
print("Ahoj, zadej svého oblíbeného Simpsna (z rodiny Simpsnů): ");
let simpson = readLine()!
if let pozice = simpsonovi.index(of: simpson) {
    print("Jo, to je můj \(pozice + 1). nejoblíbenější Simpson!")
} else {
    print("Hele, tohle není Simpson!")
}

Výstup:

Ahoj, zadej svého oblíbeného Simpsna (z rodiny Simpsů):
Homer
Jo, to je můj 1. nejoblíbenější Simpson!

Kopírování pole

Občas se může stát, že z nějakého důvodu potřebujete přesnou kopii vašeho pole. To je ve Swiftu buď velmi jednoduché a nebo poměrně zdlouhavé. Záleží totiž na tom, jestli se vaše pole skládá z hodnotových typů (Int, Double, String) nebo referenčních (instance tříd, o těch se podrobně pobavíme až v dalších Swift kurzech). V prvním případě stačí vytvořit novou proměnnou pole a to stávající do něj přiřadit. Použijeme naše pole Simpsonů, které se skládá z hodnot typu String - tedy hodnotových typů a vytvoříme jeho kopii.

var simpsonovi = ["Homer", "Marge", "Bart", "Lisa", "Maggie"]

var kopieSimpsnu = simpsonovi

Případ s referenčními datovými typy zatím nebudeme řešit.

count

count jsme si již zmínili, obsahuje délku pole. Není metodou, ale vlastností, nepíší se za ni tedy závorky ().

isEmpty

Jak asi tušíte, tato vlastnost vrátí true, pokud je naše pole prázdné. Je to lepší, než se ptát, jestli je počet (count) roven nule a z kódu je hned jasné, že nás zajímá možná prázdnost pole.

min() a max()

Matematické metody, vracející nejmenší prvek (min()), největší prvek (max()). Výsledek vrátí jako Optional, pro případ, že by pole bylo prázdné.

first a last

Již podle názvu vlastnosti vrátí první a poslední prvek.

contains()

Metoda vrací true/false podle toho, zda se prvek, uvedený v parametru metody, v daném poli nachází.

Mazání prvků

Moderní provedení pole ve Swiftu nám umožňuje pohodlně mazat prvky.

remove(at: )

Metoda remove() odstraní z pole prvek na námi zadaném indexu. Musíme si ale dát pozor, aby index skutečně existoval, jinak kód skončí chybou. Častěji asi budete chtít z pole smazat konkrétní prvek místo prvku na vybraném indexu. Swift bohužel nenabízí jednoduchou metodu, která toto zajistí, můžeme si ale pomoci metodou index(of: ), kterou již známe:

if let bartIndex = simpsonovi.index(of: "Bart") {
    simpsonovi.remove(at: bartIndex)
}

Takto můžeme z našeho pole Simpsnů smazat Barta. Myslete na to, že pole musí být deklarováno jako var, protože konstantní přes let nám nedovolí úpravy. Metoda remove(at: ) smazaný prvek zároveň vrátí, pokud byste s ním chtěli pracovat.

removeAll()

Zde není moc co vysvětlovat. Metoda jednoduše z pole odstraní všechny prvky. Dostupná je ještě varianta s parametrem keepingCapacity. Pole si totiž na pozadí drží kapacitu pro prvky a v případě potřeby se zvětšuje. Pokud máte v poli mnoho prvků, chcete je odstranit, ale víte, že jej brzy naplníte dalšími v podobném počtu, můžete Swiftu ušetřit práci s opětovným budováním kapacity. Není to ale nic důležitého a klidně používejte removeAll() bez parametru.

removeLast() a popLast()

Obě metody odstraní poslední prvek v poli a vrátí nám ho. Jak se tedy liší? Zásadně v případě, že je pole prázdné. removeLast() v takovém případě vyvolá chybu, zatímco popLast() jednoduše vrátí prázdný Optional. Pokud víte, že pole určitě nebude prázdné, bude jednoduší využít removeLast(), protože nemusíte řešit rozbalování Optional.

Tyto metody se hodí také v případě, že chcete pomocí pole emulovat datovou strukturu zásobník (Stack), kterou Swift oproti dalším jazykům nenabízí. Její princip je prostý. Funguje jako pomyslný štos papírů na stole. Nové prvky (papíry) vždy přijdou navrch a při odebírání se nejdříve dostaneme k těm vrchním - tedy těm, které byly přidány posledně. Pomocí append() metody, která přidává na konec pole a těchto removeLast()/popLast(), jednoduše docílíte stejného chování.

To by pro dnešek stačilo, můžete si s polem hrát.

V následujícím cvičení, Řešené úlohy k 7. lekci Swift, si procvičí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 21x (104.8 kB)
Aplikace je včetně zdrojových kódů v jazyce Swift

 

Předchozí článek
Typový systém: Optionals ve Swift
Všechny články v sekci
Základní konstrukce jazyka Swift
Přeskočit článek
(nedoporučujeme)
Řešené úlohy k 7. lekci Swift
Článek pro vás napsal Filip Němeček
Avatar
Uživatelské hodnocení:
10 hlasů
Autor se věnuje vývoji iOS aplikací (občas macOS)
Aktivity