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()
aRemoveRange()
. - 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.