IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

8. diel - PowerShell - Kolekcia objektov, II. časť

V minulej lekcii, PowerShell - Kolekcia objektov , sme sa zoznámili s prvej časti PowerShell kolekciami a vysvetlili sme si prácu s každou z nich.

V dnešnej lekcii kurze PowerShell frameworku si dopracujeme typy kolekcií PowerShellu.

Dynamické pole (System.Collections.ArrayList)

Dynamické pole ArrayList na rozdiel od statického poľa Array nepodporuje ochranu dátového typu. Avšak je možné vytvoriť dynamické pole pomocou statického poľa s ochranou dátového typu, viď. príklad nižšie:

[System.Collections.ArrayList]$Pole=[int[]]@(1,2,3)

Dynamické poľa na rozdiel od statického poľa (v PowerShellu pod dátovým typom [System.Collections.ArrayList]) navyše umožňuje odobratie prvku (elementov) z poľa.

Deklarácia dynamického poľa sa vykonáva podobne ako u statického pole s tým rozdielom, že tento typ údajov musíme vynútiť vždy, keď potrebujeme dynamické pole:

[System.Collections.ArrayList]$Pole=@(1,2,3)

Základné operácie s prvkami v dynamickom poli

Dynamické pole podporuje všetky operácie ako statické pole, navyše ešte však:

  • odobratie prvku z poľa - v prípade dynamického poľa sa toto vykonáva pomocou metód .Remove(), .RemoveAt() a RemoveRange().
  • vymazanie všetkých prvkov z poľa - toto sa vykonáva pomocou metódy .Clear().
  • obrátenie poradie prvkov v poli - niekedy je potrebné otočiť poradie prvkov v poli, tzn. prvok na prvom mieste bude posledný a obrátene. Toto sa vykonáva pomocou metódy .Reverse().

Príklad odobratie prvkov z poľa:

[System.Collections.ArrayList]$Pole=1..10
$Pole.Remove(8) #odstraní prvek s hodnotou 8 z pole
$Pole.RemoveAt(0) #odstraní prvek s indexem 0 (pozice v poli 1)
$Pole.RemoveRange(0,4) #odstraní prvky s indexem 0 až 4 (pozice v poli 1 až 5)

Statické pole versus dynamické pole - performance

Keď dôjde na otázku rýchlosti spracovania dát oboch dátových typov, tu je dynamické pole jasný víťaz. Poďme sa pozrieť prečo. Najprv však malá ukážka, kde otestujeme rýchlosť pridanie rovnakého počtu prvkov do oboch typov polí. K tomuto použijeme nasledujúce kúsok kódu a príkaz Measure-Command, ktorý meria dĺžku exekúcia kódu:

$ArrayList = New-Object -TypeName 'System.Collections.ArrayList'
$Array = @()

Measure-Command {
    for ($i = 0; $i -lt 10000; $i++) {
        $null = $ArrayList.Add("Adding item $i")
    }
}

Measure-Command {
    for ($i = 0; $i -lt 10000; $i++) {
        $Array += "Adding item $i"
    }
}

A tu je výsledok:

Windows PowerShell
Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 53
Ticks             : 531792
TotalDays         : 6.155E-07
TotalHours        : 1.4772E-05
TotalMinutes      : 0.00088632
TotalSeconds      : 0.0531792
TotalMilliseconds : 53.1792

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 3
Milliseconds      : 558
Ticks             : 35581670
TotalDays         : 4.11824884259259E-05
TotalHours        : 0.000988379722222222
TotalMinutes      : 0.0593027833333333
TotalSeconds      : 3.558167
TotalMilliseconds : 3558.167

Ako môžeme vidieť, v prípade typu ArrayList zabralo 53ms pridať všetky prvky do tohto poľa. Avšak pre typ Array to zabralo niekoľkonásobne viac času, a to konkrétne 3s a 56MS, čo je naozaj markantný rozdiel.

Tento rozdiel v performanciu je spôsobený systémom, ako pracuje statické a dynamické pole pri pridávaní ďalších prvkov:

  • statické polia: veľkosť statického poľa je fixná. To možno overiť pomocou vlastnosti .IsFixedSize. Pri pridaní ďalšieho prvku sa vezme posledné pridaný prvok a pôvodný obsah poľa a toto pole sa v pamäti vytvorí znovu is novo pridaným prvkom. Teda pri každom pridaní nového prvku je toto pole prakticky deklarované v pamäti znovu ako nové pole, zakaždým s fixnou veľkostí.
  • dynamické pole: veľkosť dynamického poľa nie je fixná, preto môže v pamäti počítača expandovať. Toto môžno zobraziť pomocou vlastnosti .IsFixedSize. Pri pridaní ďalšieho prvku do tohto poľa sa tento nový prvok pridá do existujúceho poľa a jeho veľkosť sa v pamäti zväčší.

Statické pole versus dynamické pole - záver

Uvedieme si pár pre a proti použitiu statického oproti dynamického poľa.

Statické pole:

  • + Podpora ochrany dátového typu
  • + Použitý ako defaultný dátový typ PowerShellu
  • - performance je naozaj pomalá v porovnaní s dynamickým poľom
  • - nemožno odoberať prvky z poľa

Dynamické pole:

  • + Niekoľkonásobne lepšie performance v porovnaní so statickým poľom
  • + Možno odoberať prvky z poľa a to hneď niekoľkými rôznymi spôsobmi
  • + Metóda .Reverse(), ktorá sa občas hodí
  • - chýba podpora ochrany dátového typu, avšak toto možno s menším úsilím implementovať

Hash tabuľka (hashtable) versus triedený slovník (OrderedDictionary)

Či už HashTable alebo OrderedDictionary, oba tieto typy sú podobné typu polia s tým rozdielom, že štruktúra prvku v hash tabuľke je vo formáte kľúč = hodnota kľúča (Key=Value).

Defaultne nie je hash tabuľka triedená, teda prvky na výstupe nemusí byť v tom poradí, v akom boli do tejto tabuľky pridané. Čo však nemusí byť vždy problém.

K tomu, aby sme docielili rovnakého poradia na výstupe aj na vstupe, použijeme triedený slovník.

  • HashTable je deklarovaná pomocou výrazu @{}.
  • OrderedDictionary je deklarovaný pomocou výrazu [ordered]@{}.

Pre oba typy však platí rovnaký zápis dát do tejto tabuľky.

HashTable:

$HashTable = @{
    Name = 'Vojtech'
    Surname = 'Kasny'
    Age = 39
}

OrderedDictionary:

$OrderedHashTable = [ordered]@{
    Name = 'Vojtech'
    Surname = 'Kasny'
    Age = 39
}

Pozrime sa na výstup premenné $HashTable, ktorá nie je triedená a premenné OrderedHashTable, ktorá už triedená je:

Windows PowerShell
$HashTable

Name                           Value
----                           -----
Name                           Vojtech
Age                            39
Surname                        Kasny

$OrderedHashTable

Name                           Value
----                           -----
Name                           Vojtech
Surname                        Kasny
Age                            39

Základné operácie s hash tabuľkou

Platí pre oba typy, triedené aj netriedené tabuľky.

Deklarácia

Vykonáva sa pomocou výrazu @{} a môže byť buď prázdna alebo s definovanými hodnotami.

Prázdna hash tabuľka:

$EmptyHashtable = @{}

Definované hash tabuľka, ktorá je už zotriedená:

$CustomHashtable = [ordered]@{
    Color = 'Red'
    Doors = 4
    Manufactured = Get-Date
}

Pridanie záznamu

Vykonáva sa pomocou metódy .Add('<key>','<value>'):

$CustomHashtable.Add('Engine','Petrol')

Meno kľúča musí byť v tabuľke unikátne.

Odobratie záznamu

Vykonáva sa pomocou metódy .Remove('<key>'):

$CustomHashtable.Remove('Doors')

Využitie hash tabuľky v praxi

Hash tabuľku možno v praxi využiť efektívne k dvom veciam:

  • k PSCustomObject u
  • ak tzv. splatting u
PSCustomObject

Hash tabuľku použijeme ako vstupné dáta pre nový custom objekt, s ktorým už vieme pracovať:

$obj = New-Object psobject -Property $CustomHashtable

výstup:

Windows PowerShell
$obj

Color     Manufactured                   Engine
-----     ------------                   ------
Red       9/26/2020 3:29:36 PM           Petrol
Splatting

Týmto označením nie je myslené nič iné, než odovzdanie vstupných parametrov príkazu pomocou hash tabuľky. Táto tabuľka je potom odovzdaná danému príkazu pomocou znaku @ (pozri. Príklad nižšie). Toto sa vykonáva pre lepšiu čitateľnosť kódu a to vtedy, keď počet vstupných parametrov na jednom riadku presiahne únosnú hranicu.

Čo je únosná hranica záleží čisto na danom vývojári. Ja osobne mám túto hranicu nastavenú vo Visual Studio Code na 160 znakov.

#Tento zápis je sice funkční, nicméně obtížně čitelný
(Get-WmiObject -Query "select WorkingSetSize from win32_process where name='system'" -EnableAllPrivileges -ComputerName $env:COMPUTERNAME -Verbose -ErrorAction Stop -Namespace root/cimv2).WorkingSetSize

#Stejný zápis pomocí tabulky hash (zde stačí netříděná tabulka)
$CommandArguments = @{
    Query = "select WorkingSetSize from win32_process where name='system'"
    EnableAllPrivileges = $true
    ComputerName = $env:COMPUTERNAME
    Namespace = 'root/cimv2'
    Verbose = $true
    ErrorAction = 'Stop'
}

Príkaz Get-WmiObject stačí potom už zavolať a odovzdať argumenty pomocou splatting:

Windows PowerShell
(Get-WmiObject @CommandArguments).WorkingSetSize

20189184

Nutné ešte spomenúť, že všetky vstupné parametre, či už skriptu či custom funkcie, sú v kóde reprezentované systémovú premennú $PSBoundParameters, ktorá je typu PSBoundParametersDictionary a možno ju využiť rovnako ako tabuľka hash:

function Write-PassedParameters {
    param (
        [parameter(Mandatory)][int[]]$Port,
        $ComputerName=$env:COMPUTERNAME
    )
    Write-Output $PSBoundParameters
}

výstup:

Windows PowerShell
Write-PassedParameters 1,2,3,4 -ComputerName localhost

Key               Value
---               -----
ComputerName      localhost
Port              {1, 2, 3, 4}

A ešte ukážka jednoduché konverzie na dátový typ PSCustomObject:

Windows PowerShell
New-Object psobject -Property (Write-PassedParameters 1,2,3,4 -ComputerName localhost)

ComputerName       Port
------------       ----
localhost          {1, 2, 3, 4}

V ďalšej lekcii, PowerShell - Cykly , sa zoznámime s PowerShell cyklami.


 

Predchádzajúci článok
PowerShell - Kolekcia objektov
Všetky články v sekcii
PowerShell
Preskočiť článok
(neodporúčame)
PowerShell - Cykly
Článok pre vás napísal Vojtěch Kašný
Avatar
Užívateľské hodnotenie:
1 hlasov
Aktivity