7. díl - Pole v Javě

Java Základní konstrukce Pole v Javě

Minule jsme si v našem Java seriálu ukázali cykly . Dnes 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, takle 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

(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 Java 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 Javu. 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 Javě 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í hranatých závorek:

int[] pole;

Pole je samozřejmě název naší proměnné. Nyní jsme však pouze deklarovali, že v proměnné bude pole intů. Nyní ho musíme založit, abychom ho mohli používat. Použijeme k tomu klíčové slovo new, které zatím nebudeme vysvětlovat. Spokojme se s tím, že je to kvůli tomu, že je pole referenční datový typ (můžeme chápat jako složitější typ):

int[] pole = new int[10];

Nyní máme v proměnné pole pole o velikosti deseti intů.

K prvkům pole potom přistupujeme přes hranatou závorku, pojďme na první index (tedy index 0) uložit číslo 1.

int[] pole = new int[10];
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:

int[] pole = new int[10];
pole[0] = 1;
for (int i = 0; i < 10; i++) {
        pole[i] = i + 1;
}

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

for (int i = 0; i < pole.length; i++) {
        System.out.print(pole[i] + " ");
}

Všimněte si, že pole má konstantu length, kde je uložena jeho délka, tedy počet prvků. Stejně tak můžeme použít metodu size(), která vrátí stejný výsledek.

Naplnění a výpis pole v Javě

Můžeme použít zjednodušenou verzi cyklu pro práci s kolekcemi, známou jako foreach. Ten projede všechny prvky v poli a jeho délku si zjistí sám. Jeho syntaxe je následující:

for (datovytyp promenna : kolekce) {
        // příkazy
}

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 foreach. Foreach nemá řídící proměnnou, není tedy vhodný pro vytvoření našeho pole a použijeme ho jen pro výpis.

int[] pole = new int[10];
pole[0] = 1;
for (int i = 0; i < 10; i++) {
        pole[i] = i + 1;
}
for (int i : pole) {
        System.out.print(i + " ");
}

Výstup programu:

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:

String[] simpsonovi = {"Homer", "Marge", "Bart", "Lisa", "Meggie"};

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ě Arrays

Java nám poskytuje třídu Arrays, která obsahuje pomocné metody pro práci s poli.

K jejímu použití je třeba ji naimportovat:

import java.util.Arrays;

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řadit a vypsat naši rodinku Simpsnů:

String[] simpsonovi = {"Homer", "Marge", "Bart", "Lisa", "Meggie"};
Arrays.sort(simpsonovi);
for (String s : simpsonovi) {
        System.out.print(s + " ");
}
Třídění/seřazení pole v Javě

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

BinarySearch()

Když pole seřadíme, umožní nám v něm Java vyhledávat prvky. Metoda binarySearch() nám vrátí index první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 poté zkontrolujeme, zda je to opravdu Simpson. Pole musí být opravdu setříděné, než metodu zavoláme!

Scanner sc = new Scanner(System.in, "Windows-1250");

String[] simpsonovi = {"Homer", "Marge", "Bart", "Lisa", "Meggie"};
System.out.println("Zadej Simpsna (z rodiny Simpsů): ");
String simpson = sc.nextLine();

Arrays.sort(simpsonovi);
int pozice = Arrays.binarySearch(simpsonovi, simpson);
if (pozice >= 0)
        System.out.println("Jo, to je Simpson!");
else
        System.out.println("Hele, tohle není Simpson!");
Vyhledání prvků v poli v Javě

CopyOfRange()

copyOfRange() již podle názvu zkopíruje část pole do jiného pole. Prvním parametrem je zdrojové pole, druhým startovní pozice a třetím konečná pozice. Metoda vrací nové pole, které je výsekem původního pole.

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:

Scanner sc = new Scanner(System.in, "Windows-1250");

System.out.println("Ahoj, spočítám ti průměr známek. Kolik známek zadáš?");
int pocet = Integer.parseInt(sc.nextLine());
int[] cisla = new int[pocet];
for (int i = 0; i < pocet; i++) {
        System.out.printf("Zadejte %d. číslo: ", i + 1);
        cisla[i] = Integer.parseInt(sc.nextLine());
}
// spočítání průměru
int soucet = 0;
for (int i: cisla) {
        soucet += i;
}
float prumer = soucet / (float)cisla.length;

System.out.printf("Průměr tvých známek je: %f", prumer);
Proměnná délka pole v Java

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.

U výpočtu průměru si všimněte, že při dělení je před jedním operandem napsáno (float), tím říkáme, že chceme dělit neceločíselně. Jistě si vzpomínáte, že při zadávání čísel při dělení jsme při 3 / 2 dostali výsledek 1 a při 3 / 2.0F dostali výsledek 1.5. Zde je princip stejný.

To by pro dnešek stačilo, můžete si s polem hrát. Příště na vás čeká překvapení ;-)


 

Stáhnout

Staženo 721x (76.35 kB)
Aplikace je včetně zdrojových kódů v jazyce java

 

  Aktivity (2)

Článek pro vás napsal David Čápka
Avatar
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.

Jak se ti líbí článek?
Celkem (20 hlasů) :
55555


 


Miniatura
Předchozí článek
Cvičení k 6. lekci Javy
Miniatura
Všechny články v sekci
Základní konstrukce jazyka Java
Miniatura
Následující článek
Cvičení k 7. lekci Javy

 

 

Komentáře
Zobrazit starší komentáře (52)

Avatar
Miroslav Melzer:

Potřeboval bych prosím vysvětlit pár drobností.

int[] pole = new int[10];
pole[0] = 1;
for (int i = 0; i < 10; i++)
        pole[i] = i + 1;

jak přesně, nebo co tady znamená to pole[i] v posledním řádku? Něco jako že to platí pro všechny prvky pole, že přistupujem hromadně ke všem prvkům ?
Druhá věc je v té proměnné delce pole.

System.out.printf("Zadejte %d. číslo: ", i + 1);
       cisla[i] = Integer.parseInt(sc.nextLine());

Tady to znamená co, to cisla [i] ? Že se to pole plní čísly od uživatele ?
A naposled nechápu proč když se použije "pole.length " , tak pro výpis potom "pole [i]"

for (int i = 0; i < pole.length; i++)
        System.out.printf("%d ", pole[i]);

a když for each cyklus tak jen "i"

for (int i : pole)
        System.out.printf("%d ", i);

Případný vysvětlení prosím spíš tak trochu jako pro debila....

 
Odpovědět 28. října 16:11
Avatar
pocitac770
Redaktor
Avatar
Odpovídá na Miroslav Melzer
pocitac770:

Jde ne o nepochopení pole, ale cyklů (tedy si to radši ještě jednou pročti).
U klasického for cyklu je to "i" proměnná přes kterou řídíme iteraci (procházení), ta se nám logicky (podle nastavených pravidel) postupně zvyšuje, pokaždé toho využijeme a použijeme tu hodnotu. Představ si to tak, že vždy místo toho "i" dosadíš číslo, pokolikáté se to už dělá (začínaje nulou).
Proměnná ve foreach funguje trochu jinak, tam jí nijak nekontrolujeme, vždy se nám dosadí přímo ona hodnota, co je v poli (takže např nemáme jak zjistit, kolikátý prvek to je, nemůžeme ho tedy ani nahradit), je to takové "zjednodušení" pro pouhé procházení pole.

 
Odpovědět 28. října 17:07
Avatar
Miroslav Melzer:

Dík, to "i" v těch cyklech mi pořád přijde nějaký divný......

 
Odpovědět 28. října 19:39
Avatar
pocitac770
Redaktor
Avatar
Odpovídá na Miroslav Melzer
pocitac770:

Jde o normální proměnnou, zde například typu int (v foreach cyklu při procházení Simpsonů je použit String kvůli typu objektů v poli), kde v klasickém for cyklu s ní nějak pracuješ ty (jako třetí člen v závorce je to, co se má udělat na konci každé iterace, to že je zde i++ neznamená, že tam nemůže být třeba "i = i * 5 - 2", taktéž ji můžeš upravit třeba někde uvnitř bloku).
Ve foreach už s tím nic nemůžeme dělat, protože to ani nemá smysl, v tu chvíli je to proměnná, jejíž obsah při každé iteraci upraví sama Java, aby byl roven dalšímu prvku v poli.

 
Odpovědět 28. října 20:45
Avatar
Miroslav Melzer:

Jakým způsobem bych naplnil pole desetinnými čísly ? Nebo kdybych chtěl zvyšovat hodnotu o třeba 0.1 ?

 
Odpovědět 1. listopadu 20:04
Avatar
pocitac770
Redaktor
Avatar
Odpovídá na Miroslav Melzer
pocitac770:

Máš to přesně napsáno v mém předchozím komentáři, stačí číst

Jde o normální proměnnou, zde například typu int

Ano, můžeš použít double

to že je zde i++ neznamená, že tam nemůže být třeba "i = i * 5 - 2"

No, tohle mluví samo za vše

Případně, pokud ti to přijde složité, tak můžeš použít nějakou proměnnou mimo cyklus, a vždy ji v každé iteraci upravit o onu hodnotu, ale jde o úplně to samé

Editováno 2. listopadu 7:21
 
Odpovědět 2. listopadu 7:20
Avatar
Miroslav Melzer:

Proč to nefunguje takhle: ?

double[] pole= new double [10];
     for (double i = 0; i<10; i++)
         pole[i] =  i + 0.1;
     for(double i :pole)
       System.out.printf("%f ", i);

       float [] pole = new float[10];
       for(float i=0F; i<10F; i++)
           pole[i] = i + 0.1;
       for(float i :pole)
           System.out.printf("%f",i);
 
Odpovědět 2. listopadu 19:14
Avatar
pocitac770
Redaktor
Avatar
Odpovídá na Miroslav Melzer
pocitac770:

Protože... Když máš pole, co má 10 míst, tak ho musíš naplnit 10 prvky. A pokud budeš přičítat pořád 0.1 tak

  1. Kolikrát proběhne iterace? No přeci 100x
  2. Jaké indexy to bude vybírat? Ano, i desetinné

V tuto chvíli, ok, spíš jsem se ti snažil odpovědět na konkrétní otázky než na celek, když dojde na realizaci, tak je to už o přemýšlení...
Pokud chceš přes tu samou proměnnou zároveň přistupovat k indexu, a zároveň přičítat k hodnotě, aby jsi pole plnilpo desetinách, tak si budeš muset udělat nějaký konvektor.
Např. budeš mít řídící proměnnou typu int, klasicky přičítat i++, a když budeš potřebovat hodnotu, tak si ji vezmeš jako i/10. Nebo naopak, budeš mít řídící proměnnou double, a budeš si vždy brát index jako i*10.

 
Odpovědět 2. listopadu 21:32
Avatar
pocitac770
Redaktor
Avatar
Odpovídá na Miroslav Melzer
pocitac770:

EDIT: blbě jsem četl, myslel jsem, že v řídícím příkazu (to za druhým středníkem) máš to i += 0.1
V tomto případě si zase uvědom, co se děje. Nejprve je tam 0, a doplníš 0 + 0.1, neboli 0.1. Následně je tam 1, a doplníš 1 + 0.1, neboli 1.1. Zde byl problém v tomto konrétním případě. Jinak pořád platí vše viz výše...

 
Odpovědět 2. listopadu 21:38
Avatar
Oskar Nový
Člen
Avatar
Oskar Nový:

%d se používá při celá čísla %f pro desetiná a %s pro Stringy (textové řetězce).
Printf musíš použít proto aby ti ty % fungovala.

 
Odpovědět 21. listopadu 18:48
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 10 zpráv z 62. Zobrazit vše