Letní akce! Lákají tě IT školení C#, Javy a PHP v Brně? Přihlas se a napiš nám do zpráv kód "BRNO 500" pro slevu 500 Kč na libovolný brněnský kurz. Lze kombinovat se slevami uvedenými u školení i použít pro více kurzů. Akce končí 28.7.

Lekce 7 - Pole v Kotlin

Kotlin Základy Pole v Kotlin

ONEbit hosting Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci kurzu, Typový systém: Null safety v Kotlin, jsme se naučili používat nullovatelné typy. Dnes si v Kotlin tutoriálu představíme datovou strukturu pole a vyzkoušíme si, co všechno umí.

Pole

Představme si, že chceme uložit nějaké údaje o více prvcích. Např. chceme 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 v Kotlin

(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). Kotlin se řadí k těm moderním, nemusíte se starat o velikost polí (dokonce ji ani nemůžete pevně zadat) a přidávat prvky můžete i do již vytvořeného pole.

Pole deklarujeme pomocí funkce arrayOf():

var pole = arrayOf<Int>()

Výraz pole je samozřejmě název naší proměnné. Nyní jsme vytvořili prázdné pole Intů.

Nové prvky do pole nejdříve přidáme operátorem +=. V našem případě za něj uvedeme přidávané číslo jako Int, který se uloží na konec pole:

var pole = arrayOf<Int>()
pole += 34

Do pole můžeme takto přidat i další pole stejného typu (tedy typu Int v našem případě), jehož prvky se do pole přidají.

K prvkům pole přistupujeme přes hranatou závorku, kam uvedeme index prvku. Můžeme to udělat samozřejmě pouze tehdy, když prvek na daném indexu existuje. Zkusme si to:

var pole = arrayOf<Int>()
pole += 34
print(pole[0])

Vypsali jsme prvek na indexu 0, tedy první, jelikož jsou indexy od nuly. Na výstupu opravdu vidíme číslo 34, které je tam uložené:

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 = arrayOf<Int>()
for (i in 1..10) {
        pole += i
}

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

for (i in pole) {
        print("$i ")
}

Nyní už je lépe vidět síla for cyklu v Kotlin. Stačí za in místo definované řady čísel vložit pole a cyklus projde všechny prvky. V těle cyklu k nim poté můžeme přistupovat a např. je vypsat:

1 2 3 4 5 6 7 8 9 10

Pole má vlastnost size, kde je uložen počet jeho 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 funkci arrayOf() a do závorek napíšeme prvky, které oddělujeme čárkou. Tentokrát si zkusíme vytvořit pole textových řetězců:

val simpsonovi = arrayOf("Homer", "Marge", "Bart", "Lisa", "Meggie")

Protože nyní nechceme, aby nám někdo obsah pole měnil, deklarujeme ho pomocí val a tím se pole stává konstantní. Vynechali jsme upřesnění typu, Kotlin z prvků totiž snadno pozná, že jde o pole Stringů. Samozřejmě nám ale nic nebrání typ uvést:

val simpsonovi: Array<String> = arrayOf("Homer", "Marge", "Bart", "Lisa", "Meggie")

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 jej nebudeme 10x počítat, ale spočítáme jej jednou a uložíme do pole, odtud poté daný výsledek jen načteme.

Metody pole

Na polích nám Kotlin poskytuje pomocné metody pro práci s nimi. Pojďme se na ně podívat:

sort() a sorted()

Jak již název napovídá, metody nám pole seřadí. Metoda sort() seřadí již existující pole (takže musí být deklarované pomocí 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é. Stringy třídí podle abecedy, čísla podle velikosti. Zkusme si setřídit a vypsat naši rodinku Simpsnů:

val simpsonovi: Array<String> = arrayOf("Homer", "Marge", "Bart", "Lisa", "Meggie")
simpsonovi.sort()
for (simpson in simpsonovi) {
        println(simpson)
}

Výsledek:

Bart
Homer
Lisa
Maggie
Marge

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

val simpsonovi: Array<String> = arrayOf("Homer", "Marge", "Bart", "Lisa", "Meggie")

val simpsonovi_sorted = simpsonovi.sortedArray()
for (simpson in simpsonovi_sorted) {
        println(simpson)
}
Bart
Homer
Lisa
Maggie
Marge

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

reverse() a reversedArray()

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

val simpsonovi: Array<String> = arrayOf("Homer", "Marge", "Bart", "Lisa", "Meggie")
simpsonovi.sort()
simpsonovi.reverse()
for (simpson in simpsonovi) {
        println(simpson)
}

Výsledek:

Meggie
Marge
Lisa
Homer
Bart

indexOf()

Metoda nám najde první výskyt daného prvku v poli a vrátí jeho index jako Int. Může se stát, že prvek v poli není, v takovém případě metoda vrátí -1. Vytvoříme si jednoduchý program, který bude předpokládat, že Simpsni jsou v poli seřazení podle oblíbenosti. Když uživatel nějakého zadá, vypíšeme mu kolikátý je nebo že v poli není.

val simpsonovi = arrayOf("Homer", "Marge", "Bart", "Lisa", "Meggie")
println("Ahoj, zadej svého oblíbeného Simpsna (z rodiny Simpsů): ")
val simpson = readLine()!!
val pozice = simpsonovi.indexOf(simpson)
if (pozice != -1) {
        println("Jo, to je můj ${pozice + 1}. nejoblíbenější Simpson!")
} else {
        println("Hele, tohle není Simpson!")
}

Výsledek:

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

size

size jsme si již zmínili, obsahuje počet prvků v poli. Není metodou, ale vlastností, nepíší se za ni tedy závorky ().

isEmpty()

Jak asi tušíte, tato metoda vrátí true, pokud je naše pole prázdné. Její použití je čitelnější, než se ptát pomocí pole.size == 0. Z kódu je hned jasné, že nás zajímá možnost když je pole prázdné.

min() a max()

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

first() a last()

Již podle názvu vlastnosti vrátí první a poslední prvek. Návratové hodnoty jsou opět nullable.

contains()

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

To by pro dnešek stačilo, můžete si s polem hrát. V příští lekci, Textové řetězce v Kotlin podruhé - Práce se znaky, na vás čeká překvapení ;-)


 

Stáhnout

Staženo 44x (16.5 kB)

 

 

Článek pro vás napsal Samuel Kodytek
Avatar
Jak se ti líbí článek?
1 hlasů
Autor se věnuje Javě, Kotlinu, PHP, C, HTML. Zajímá ho spíše game design.
Miniatura
Všechny články v sekci
Základní konstrukce jazyka Kotlin
Miniatura
Následující článek
Cvičení k 7. lekci Kotlin
Aktivity (3)

 

 

Komentáře

Avatar
neutr
Člen
Avatar
neutr:21. dubna 12:11

Opravdu jsem velice zvědavý co bude tím překvapením. Velice bych pohledával například automatické předimenzování pro přídání a ubrání prvku spolu s automatickým přetříděním. Také bych uvítal možnost vkládat prvky do pole aniž bych musel přídávat prvek na konec a pak mu udělat místo oditerováním zbytku na poslední (nový), nebo to řešit pomocí split/merge. Ještě více bych si cenil těchto operací na vícedimenzionálních polích. Zejména u kolekcí.

Konkrétně klasická array(x,y), nebo i array(x,y,z) do typu array(x)(y), respektive array(x)(y)(z) - tedy do nesymetricých kolekcí, nebo alepoň sofistikovanější operace s Empty prvky symetrických polí (objektů - matic).


Mimo svých velkých očekávání bych si dovolil poznámku k popisu metod pole - příklad sort() a sorted(). Musel jsem se 3x vrátit aby mi došlo, že v podstatě sort() provede setřídění pro výstup, ale zůstane v původním rozložení, zatímco sorted() udělá změnu přímo v array. On totiž výstup podle doporučení vydá úplně stejný výsledek. Určitě není snadné najít rozdíl

val simpsonovi_sorted = simpsonovi.sor­tedArray()
poznámkou - simpsonovi_sorted = arrayOf("Bart", "Homer", "Lisa", "Maggie", "Marge")
simpsnovi_sorted
for (simpson in simpsonovi_sorted) {

Pokud se mýlím tak mne opravte. Pole zpracované jako sorted() stačí vypsat podle indexu, ale třídit se už nemusí - je už setříděné. Ono to tam sice je, ale je to málo zřetelné když hledáme rozdíl. Díky

 
Odpovědět 21. dubna 12:11
Avatar
gcx11
Redaktor
Avatar
Odpovídá na neutr
gcx11:21. dubna 19:24

Pokud člověk neví předem, kolik prvků potřebuje uložit, tak se hodí MutableList.

val items = mutableListOf<Int>()
items.add(1)
items.add(2)

S tím automatickým přetříděním je to složitější. Nejlepší je mít nějakou vlastní kolekci, která využívá toho, že je zbytek setříděný, ale to je složitější na napsání a bohužel Kotlin (Java) přímo něco takového nemá.

Co by šlo použít, tak je napsat si vlastní extension funkci. Příklad:

inline fun <reified T: Comparable<T>> MutableList<T>.addAndSort(item: T) {
    add(item)
    sort()
}

fun main(args: Array<String>) {
    val items = mutableListOf(7, 3, 6)
    items.addAndSort(5)
    print(items) // [3, 5, 6, 7]
}

Mimo svých velkých očekávání bych si dovolil poznámku k popisu metod pole - příklad sort() a sorted()

Je to složitější, sort provede setřídění na vstupním poli a nevrací nic, sorted vrátí nový seznam (List), který obsahuje seřazená data, ale původní pole nechá být a sortedArray dělá to samé, akorát vrací zase pole (Array).

 
Odpovědět  +1 21. dubna 19:24
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 2 zpráv z 2.