LINUXSOFT.cz Přeskoč levou lištu

ARCHIV



   

> Perl (47) - Složitější datové struktury

Dnes si zadefinujeme první datové struktury skládající se z několika do sebe vnořených polí a hashů.

29.11.2006 06:00 | Jiří Václavík | Články autora | přečteno 22332×

Vytváření složitých datových struktur

Odkaz na odkaz

Jednou z hodnot, které může vracet funkce ref, je "REF". To znamená, že odkaz může ukazovat na jiný odkaz. Ukažme si to opět na reprezentaci v paměti. Máme nějaký obyčejný odkaz

$x = "HODNOTA";
$r_x = \$x;

s takovou reprezentací v paměti:

AdresaHodnotaProměnná
3
4
5"HODNOTA"$x
6
7
8
9
10SCALAR(5)$r_x
11

Teď vytvoříme odkaz na proměnnou $r_x, která je také odkazem.

$rr_x = \$r_x;

$rr_x se v paměti uloží na novou adresu.

AdresaHodnotaProměnná
3
4
5"HODNOTA"$x
6
7REF(10)$rr_x
8
9
10SCALAR(5)$r_x
11

$rr_x ukazuje na hodnotu proměnné $r_x, ale ta ukazuje dále na hodnotu "HODNOTA". Všechny tyto 3 proměnné ukazují postupnou dereferencí na stejnou adresu v paměti. A tak můžeme pokračovat stále dál.

Dereferenci pak provádíme postupným přidáváním dolarů. Všechny následující příkazy tisknou hodnotu na adrese 5.

print $x;
print $$r_x;
print $$$rr_x;

Při vytváření vnořených odkazů na konstantní skalár je přípustné dokonce i použití více zpětných lomítek najednou. Sice se to neužívá, ale pro zajímavost můžeme uvést alespoň ukázku.

$rrrr_x = \\\\"HODNOTA";
print $$$$$rrrr_x;

Pole odkazů na pole

Jak už víme, pole v Perlu může obsahovat pouze skalární hodnoty. Právě proto zní nadpis Pole odkazů a nikoliv Dvojrozměrné pole. Vícerozměrná pole Perl nepodporuje, ale lze je nasimulovat právě pomocí odkazů. A to až do té míry, že se dá s polem odkazů na pole pracovat prakticky stejně, "jako by se pracovalo s dvojrozměrným polem".

Vytvoření datové struktury

Pole odkazů na pole je vůbec nejjednodušší složitější datová struktura. Nejprve vytvoříme několik obyčejných polí.

@pole1 = (1, 2, 3);
@pole2 = (4, 5, 6);
@pole3 = (7, 8, 9, 10);

Odkazy na tyto pole uložíme do jiného pole. Dosáhneme toho jedním ze dvou různých zápisů. Ten první asi nikoho nepřekvapí.

@pole_odkazu = (\@pole1, \@pole2, \@pole3);

Ovšem lze toho docílit i umístěním zpětného lomítka před otevírací závorku seznamu.

@pole_odkazu = \(@pole1, @pole2, @pole3);

@pole_odkazu je právě ono pole odkazů na jiná pole. Za chvíli si ukážeme, jak se s ním pracuje.

Lepší způsob definice složitých datových struktur však nabízejí, jak víme z předchozího dílu, anonymní data. Díky nim totiž umíme vytvořit odkaz na pole bez toho, abychom toto pole měli. Použití je jednoduché - žádné proměnné @pole1, @pole2 atd. nevytváříme, ale jako prvky pole @pole_odkazu přímo předáme anonymní data.

@pole_odkazu = (
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9, 10]
);

Toto pole je identické s posledně vytvořeným, ale zápis je názornější.

Práce s polem odkazů na pole

Nyní, když máme vytvořenou datovou strukturu, z ní můžeme získávat hodnoty. Pole, na něž ukazuje prvek pole @pole_odkazu s indexem 0, získáme a vytiskneme tímto způsobem.

print @{$pole_odkazu[0]};

Složené závorky jsou tu proto, abychom změnili prioritu vyhodnocování. Potřebujeme získat pro index vyšší prioritu než pro dereferenci. Samotné $pole_odkazu[0] obsahuje odkaz na pole (proto se musí vyhodnotit jako první). Odkaz pak dereferencujeme.

Přístup k jednotlivým prvkům získáme přidáním indexu na konec (a samozřejmě změnou zavináče za dolar).

print ${$pole_odkazu[0]}[2];

Tento ne příliš přehledný zápis používat nemusíme. Existuje totiž operátor šipky.

print $pole_odkazu[0]->[2];

Zápis má stejný význam jako ten předchozí. Ale to není vše. Můžeme jít ještě dál a šipky mezi indexy vynechat.

print $pole_odkazu[0][2];

Zde vidíme, že práce s dvojrozměrným polem z jiných jazyků a polem odkazů na pole se prakticky neliší. Proto budeme dále tyto dva pojmy pro lepší pochopitelnost textu zaměňovat.

Počítání s maticemi

Abychom si procvičili práci s datovými strukturami, ukážeme si dále několik příkladů. Typickou ukázkou pro použití pole polí jsou operace s maticemi. Matice není nic jiného, než obdélníkové dvojrozměrné pole. Rozebereme si součet a součin matic. V archivu CPAN existují moduly, které tyto operace zvládnou samy (například Math::MatrixReal), my si však napíšeme programy vlastní.

Součet matic

Implementujeme si funkci, která sečte 2 matice. Sčítané matice musejí mít stejný počet řádků a sloupců. Pro součet matic A a B platí:

Součet matic
Součet matic

pro všechny dvojice ij, kde C je výsledná matice a aij, bij, resp. cij jsou odpovídající prvky matice A, B, resp. C na řádku i a sloupci j.

Sčítat matice bude procedura secti_matice. secti_matice přijme jako argument odkazy na 2 matice. V této proceduře musí být také zkontrolováno, zda je vůbec možné matice sečíst. To znamená zkontrolovat, zda mají obě matice stejný počet řádků a sloupců. Budeme předpokládat, že matice jsou obdélníkové.

Než se pustíme do řešení, poznamenejme, že v praxi bychom operace s maticemi nejspíše prováděli pomocí objektů. Jelikož čas objektů v seriálu teprve nastane, spokojíme se s neobjektovým provedením.

Pojďme tedy začít pracovat na funkci secti_matice. Z přijatých odkazů je snadné získat počet řádků. Stačí dereferencovat a skalární vyjádření získaných polí porovnat.

sub secti_matice {
    my($r_A, $r_B) = @_;

    die "Matice A a B maji jiny pocet radku!\n" if @$r_A != @$r_B;

    ...
}

Pro názorost nyní v podprogramech voláme die, ale ve výsledném programu tato volání nahradíme.

Dále musíme zkontrolovat, zda mají matice i stejný počet sloupců. Uděláme to pro nulté řádky matic. (nultý prvek obsahuje odkaz na pole - toto pole musí mít u obou matic stejný počet prvků).

    die "Matice A a B nemaji stejny pocet sloupcu!\n" if scalar @{$r_A->[0]} != scalar @{$r_B->[0]};

Předpokládáme, že všechny řádky mají stejný počet sloupců.

Nyní jsou všechny podmínky splněny, takže můžeme matice sečíst. Máme počet řádků i počet sloupců. Zbývá jen napsat cyklus, ve kterém vytvoříme matici C.

    my $radku = @$r_A;
    my $sloupcu = @{$r_A->[0]};

    for (my $i=0; $i<$radku; $i++){
        for(my $j; $j<$sloupcu; $j++){
            $C[$i][$j] = $A[$i][$j] + $B[$i][$j];
        }
}

To je podprogram secti_matice. Nyní napíšeme ukázkové tělo programu, který ho používá.

my @A = (
    [2, 3, 5, 2],
    [7, -8, 12, 4],
    [4, 5, 0, 7]
);

my @B = (
    [8, 7, 5, 8],
    [16, -4, -10, 0],
    [0, -1, 7, 0]
);

my @C = secti_matice(\@A, \@B);
tiskni_matici(\@C);

Podprogram tiskni_matici bude vypadat podobně jako secti_matice. Lišit se bude jen v tom, že odpadnou kontroly a místo sčítání se bude tisknout.

sub tiskni_matici {
    my ($r_matice) = @_;

    my $radku = @$r_matice;
    my $sloupcu = @{$r_matice->[0]};

    for (my $i=0; $i<$radku; $i++){
        for (my $j; $j<$sloupcu; $j++){
            printf "%8.1f ", $$r_matice[$i][$j];
        }
        print "\n";     }
}

Zdrojový kód

Součin matic

Vytvoříme další podprogram pro počítání s maticemi. Tentokrát to bude o jeden cyklus složitější, protože půjde o násobení. Součin matic má význam jen tehdy, má-li matice A stejný počet sloupců jako matice B řádků. Připomeňme si opět vztah.

Součin matic
Součin matic

pro všechny dvojice ij, kde C je výsledná matice, aij, bij, resp. cij jsou prvky matice A, B, resp. C na řádku i a sloupci j a m je počet sloupců matice A a zároveň počet řádků matice B.

Stejně jako u součtu matic musíme zkontrolovat zda má násobení smysl. Počet sloupců matice A musí být stejný jako počet řádků matice B.

    die "Matice A ma jiny pocet sloupcu nez matice B radku!\n" if @{$r_A->[0]} != @$r_B;

Pokračujme ale dále v podprogramu vynasob_matice. Teď totiž přichází na řadu hlavní část programu.

Vnořeny do sebe budou 3 cykly. Každý řádek matice A (1. cyklus) bude vynásoben se všemi sloupci matice B (2. cyklus). Každé násobení řádek × sloupec bude navíc rozloženo na násobení odpovídajících si prvků (pro každý prvek se bude počítat aik * bkj). Proto musíme použít 3. cyklus o tolika iteracích, kolik má A sloupců, resp. B řádků.

    for (my $i=0; $i<$A_radku; $i++){
        for (my $j; $j<$B_sloupcu; $j++){
            $prvek = 0;
            for (my $k=0; $k<$A_sloupcu; $k++){
                $prvek += $r_A->[$i][$k] * $r_B->[$k][$j];
            }
            $C[$i][$j] = $prvek;
        }
    }

Teď jen upravit tělo programu a vstupní matice a můžeme spustit program. Podprogram tiskni_matici upravovat nemusíme.

Zdrojový kód

Hash polí

Než se pustíme do libovolně složitých datových struktur, musíme si ukázat, jak do jejich tvorby zapojit hashe. Proto se tedy ještě krátce podíváme na další datovou strukturu, kteroužto je hash polí. Takový hash obsahuje jako své hodnoty odkazy na pole.

Hash bude obsahovat jednoduchou databázi knih, tříděných podle témat. Tedy každému tématu přiřadíme několik knih. Anonymní pole s názvy knih budou hodnotami hashe.

%knihy = (
    "Perl" => ["Programování v Perlu pro pokročilé", "Perl pro zelenáče",
"Myslíme v jazyku Perl"],
    "C++" => ["Mistrovství v C++", "Myslíme v C++"],
    "Java" => ["Java - příručka programátora", "Začínáme programovat"],
);

A teď můžeme se strukturou pracovat. Pokud chceme vypsat knihy o Perlu, zapíšeme následující příkaz.

print "Knihy o Perlu: ", @{$knihy{"Perl"}};

Podobně, chceme-li přidat nějakou další knihu.

push(@{$knihy{"Java"}}, "Jáva - dějiny ostrova");

Na závěr poznamenejme, že při vytváření anonymních polí je leckdy výhodné použití ozávorkování pomocí qw. V našem případě seznamu knih to bohužel použít nelze, ale pokud by položky byly jednoslovné, mohli bychom psát zhruba toto.

%struktura = (
    "Téma1" => [qw(polozka1 polozka2 polozka3 polozka4)],
    "Téma2" => [qw(polozka1 polozka2 polozka3 polozka4)],
    "Téma3" => [qw(polozka1 polozka2 polozka3 polozka4)],
);

Verze pro tisk

pridej.cz

 

DISKUZE

Skalární kontext 11.12.2006 18:11 Dunric




Příspívat do diskuze mohou pouze registrovaní uživatelé.
> Vyhledávání software
> Vyhledávání článků

28.11.2018 23:56 /František Kučera
Prosincový sraz spolku OpenAlt se koná ve středu 5.12.2018 od 16:00 na adrese Zikova 1903/4, Praha 6. Tentokrát navštívíme organizaci CESNET. Na programu jsou dvě přednášky: Distribuované úložiště Ceph (Michal Strnad) a Plně šifrovaný disk na moderním systému (Ondřej Caletka). Následně se přesuneme do některé z nedalekých restaurací, kde budeme pokračovat v diskusi.
Komentářů: 1

12.11.2018 21:28 /Redakce Linuxsoft.cz
22. listopadu 2018 se koná v Praze na Karlově náměstí již pátý ročník konference s tématem Datová centra pro business, která nabídne odpovědi na aktuální a často řešené otázky: Jaké jsou aktuální trendy v oblasti datových center a jak je optimálně využít pro vlastní prospěch? Jak si zajistit odpovídající služby datových center? Podle jakých kritérií vybírat dodavatele služeb? Jak volit vhodné součásti infrastruktury při budování či rozšiřování vlastního datového centra? Jak efektivně datové centrum spravovat? Jak co nejlépe eliminovat možná rizika? apod. Příznivci LinuxSoftu mohou při registraci uplatnit kód LIN350, který jim přinese zvýhodněné vstupné s 50% slevou.
Přidat komentář

6.11.2018 2:04 /František Kučera
Říjnový pražský sraz spolku OpenAlt se koná v listopadu – již tento čtvrtek – 8. 11. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma umění a technologie, IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář

4.10.2018 21:30 /Ondřej Čečák
LinuxDays 2018 již tento víkend, registrace je otevřená.
Přidat komentář

18.9.2018 23:30 /František Kučera
Zářijový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 20. 9. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář

9.9.2018 14:15 /Redakce Linuxsoft.cz
20.9.2018 proběhne v pražském Kongresovém centru Vavruška konference Mobilní řešení pro business. Návštěvníci si vyslechnou mimo jiné přednášky na témata: Nejdůležitější aktuální trendy v oblasti mobilních technologií, správa a zabezpečení mobilních zařízení ve firmách, jak mobilně přistupovat k informačnímu systému firmy, kdy se vyplatí používat odolná mobilní zařízení nebo jak zabezpečit mobilní komunikaci.
Přidat komentář

12.8.2018 16:58 /František Kučera
Srpnový pražský sraz spolku OpenAlt se koná ve čtvrtek – 16. 8. 2018 od 19:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát jsou tématem srazu databáze prezentaci svého projektu si pro nás připravil Standa Dzik. Dále bude prostor, abychom probrali nápady na využití IoT a sítě The Things Network, případně další témata.
Přidat komentář

16.7.2018 1:05 /František Kučera
Červencový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 7. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát bude přednáška na téma: automatizační nástroj Ansible, kterou si připravil Martin Vicián.
Přidat komentář

   Více ...   Přidat zprávičku

> Poslední diskuze

31.7.2023 14:13 / Linda Graham
iPhone Services

30.11.2022 9:32 / Kyle McDermott
Hosting download unavailable

13.12.2018 10:57 / Jan Mareš
Re: zavináč

2.12.2018 23:56 / František Kučera
Sraz

5.10.2018 17:12 / Jakub Kuljovsky
Re: Jaký kurz a software by jste doporučili pro začínajcího kodéra?

Více ...

ISSN 1801-3805 | Provozovatel: Pavel Kysilka, IČ: 72868490 (2003-2024) | mail at linuxsoft dot cz | Design: www.megadesign.cz | Textová verze