Všechno, co jste chtěli vědět o polích

Pole jsou základní součástí většiny programovacích jazyků. Jedná se o kolekci hodnot nebo objektů, kterým se obtížně vyhněte. Pojďme se blíže podívat na pole a všechno, co nabízejí.

Poznámka:

původní verze tohoto článku se objevila na blogu napsaného @KevinMarquette. Tým PowerShellu děkujeme Kevinovi za sdílení tohoto obsahu s námi. Prosím, podívejte se na jeho blog na PowerShellExplained.com.

Co je pole?

Začnem základním technickým popisem polí a jejich používání většinou programovacích jazyků, než se přesunu na jiné způsoby, jak je PowerShell využívá.

Pole je datová struktura, která slouží jako kolekce více položek. Pomocí indexu můžete iterovat pole nebo přistupovat k jednotlivým položkám. Pole se vytvoří jako sekvenční blok paměti, kde každá hodnota je uložena přímo vedle druhé.

S každou z těchto podrobností se budu zabývat postupně.

Základní použití

Vzhledem k tomu, že pole jsou taková základní funkce PowerShellu, existuje jednoduchá syntaxe pro práci s nimi v PowerShellu.

Vytvořte pole

Prázdné pole lze vytvořit pomocí @()

PS> $data = @()
PS> $data.Count
0

Můžeme vytvořit pole a naplnit ho hodnotami jednoduše tak, že je umístíme do závorek @().

PS> $data = @('Zero','One','Two','Three')
PS> $data.Count
4

PS> $data
Zero
One
Two
Three

Toto pole obsahuje 4 položky. Když zavoláme proměnnou $data, zobrazí se seznam položek. Pokud se jedná o pole řetězců, získáme jeden řádek na jeden řetězec.

Můžeme deklarovat pole na více řádcích. Čárka je v tomto případě volitelná a obecně se vynechává.

$data = @(
    'Zero'
    'One'
    'Two'
    'Three'
)

Raději deklaruji pole na více řádcích. Při použití správy zdrojového kódu se nejen snadněji čte, když máte více položek, ale také usnadňuje porovnání s předchozími verzemi.

Jiná syntaxe

Běžně se rozumí, že @() je syntaxe pro vytvoření pole, ale seznamy oddělené čárkami fungují většinu času.

$data = 'Zero','One','Two','Three'

Write-Output k vytváření polí

Jeden skvělý malý trik stojí za zmínku je, že můžete použít Write-Output k rychlému vytváření řetězců v konzole.

$data = Write-Output Zero One Two Three

To je užitečné, protože když parametr přijímá řetězce, nemusíte do řetězců zadávat uvozovky. Nikdy bych to neudělal ve skriptu, ale v konzoli je to férová hra.

Přístup k položkám

Teď, když máte pole s položkami, můžete k těmto položkám přistupovat a aktualizovat je.

Offset

Pro přístup k jednotlivým položkám používáme hranaté závorky [] s hodnotou posunu počínaje hodnotou 0. Takto získáme první položku v našem poli:

PS> $data = 'Zero','One','Two','Three'
PS> $data[0]
Zero

Důvodem, proč zde použijeme nulu, je to, že první položka je na začátku seznamu, takže k tomu použijeme posun 0 položek. Abychom se dostali k druhé položce, museli bychom pro přeskočení první položky použít posun 1.

PS> $data[1]
One

To by znamenalo, že poslední položka je na offsetu 3.

PS> $data[3]
Three

Rejstřík

Teď vidíte, proč jsem vybral hodnoty, které jsem udělal pro tento příklad. Tento posun jsem představil jako posun, protože to je to, co skutečně je, ale tento posun se častěji označuje jako index. Index, který začíná na 0. Pro zbytek tohoto článku budu nazývat offset indexem.

Speciální triky indexu

Ve většině jazyků můžete zadat pouze jedno číslo jako index a získáte zpět jednu položku. PowerShell je mnohem flexibilnější. Můžete použít více indexů najednou. Zadáním seznamu indexů můžeme vybrat několik položek.

PS> $data[0,2,3]
Zero
Two
Three

Položky se vrátí na základě pořadí zadaných indexů. Pokud duplikujete index, získáte tuto položku dvakrát.

PS> $data[3,0,3]
Three
Zero
Three

Pomocí integrovaného operátoru .. můžeme zadat posloupnost čísel.

PS> $data[1..3]
One
Two
Three

To funguje i obráceně.

PS> $data[3..1]
Three
Two
One

Záporné hodnoty indexu můžete použít k posunu od konce. Pokud tedy potřebujete poslední položku v seznamu, můžete použít -1.

PS> $data[-1]
Three

Zde je jedno slovo varování k operátoru ... Sekvence 0..-1 a -1..0 se vyhodnocuje na hodnoty 0,-1 a -1,0. Je snadné vidět $data[0..-1] a myslet si, že by se výčet vztahoval na všechny položky, pokud zapomenete tento detail. $data[0..-1] vám poskytne stejnou hodnotu jako $data[0,-1] tím, že získáte první a poslední položku v matici (a žádnou z ostatních hodnot). Tady je větší příklad:

PS> $a = 1,2,3,4,5,6,7,8
PS> $a[2..-1]
3
2
1
8

To je stejné jako:

PS> $a[2,1,0,-1]
3
2
1
8

Mimo hranice

Pokud se ve většině jazyků pokusíte získat přístup k indexu položky, která je za koncem pole, dojde k nějaké chybě nebo výjimce. PowerShell tiše nevrátí nic.

PS> $null -eq $data[9000]
True

Nelze indexovat do pole s hodnotou null.

Pokud je proměnná $null a pokusíte se ji indexovat jako pole, zobrazí se System.Management.Automation.RuntimeException výjimka se zprávou Cannot index into a null array.

PS> $empty = $null
PS> $empty[0]
Error: Cannot index into a null array.

Než se tedy pokusíte o přístup k prvkům uvnitř, ujistěte se, že pole nejsou $null.

Počet

Pole a další kolekce mají Count vlastnost, která vám řekne, kolik položek je v poli.

PS> $data.Count
4

PowerShell 3.0 přidal do většiny objektů vlastnost Count. Můžete mít jediný objekt a ten by vám měl poskytnout počet 1.

PS> $date = Get-Date
PS> $date.Count
1

I $null má vlastnost Count s tím rozdílem, že vrací 0.

PS> $null.Count
0

Zde jsou některé pasti, kterými se budu zabývat při kontrole $null nebo prázdných polí později v tomto článku.

Chyby o jedno

Vytvoří se běžná programovací chyba, protože pole začínají indexem 0. Chyby typu off-by-one mohou být zavedeny dvěma způsoby.

První je, když si mentálně představujete, že chcete druhou položku, a použijete index 2, ale ve skutečnosti získáte třetí položku. Nebo si myslíte, že máte čtyři položky a chcete poslední položku, takže počet použijete pro přístup k poslední položce.

$data[ $data.Count ]

PowerShell vám to dokonale umožní a poskytne vám přesně tu položku, která se nachází na indexu 4: $null. Měli byste používat $data.Count - 1 nebo -1, o které jsme se dozvěděli výše.

PS> $data[ $data.Count - 1 ]
Three

Tady můžete použít index -1 k získání posledního prvku.

PS> $data[ -1 ]
Three

Lee Dailey mi také ukázal, že můžeme použít $data.GetUpperBound(0) k získání maximálního indexu.

PS> $data.GetUpperBound(0)
3
PS> $data[ $data.GetUpperBound(0) ]
Three

Druhým nejběžnějším způsobem je iterace seznamu a nezastavování ve správný čas. Znovu se k tomu vrátím, až budeme mluvit o použití smyčky for.

Aktualizace položek

Stejný index můžeme použít k aktualizaci existujících položek v poli. To nám dává přímý přístup k aktualizaci jednotlivých položek.

$data[2] = 'dos'
$data[3] = 'tres'

Pokud se pokusíme aktualizovat položku, která je za posledním prvkem, zobrazí se Index was outside the bounds of the array. chyba.

PS> $data[4] = 'four'
Index was outside the bounds of the array.
At line:1 char:1
+ $data[4] = 'four'
+ ~~~~~~~~~~~~~
+ CategoryInfo          : OperationStopped: (:) [], IndexOutOfRangeException
+ FullyQualifiedErrorId : System.IndexOutOfRangeException

Později se k tomu vrátím, až budu mluvit o tom, jak pole zvětšit.

Iterace

V určitém okamžiku možná budete muset procházet nebo iterovat celý seznam a provádět určité akce pro každou položku v poli.

Potrubí

Pole a kanál PowerShellu jsou určené pro sebe. Toto je jeden z nejjednodušších způsobů zpracování těchto hodnot. Když předáte pole do kanálu, každá položka uvnitř pole se zpracuje jednotlivě.

PS> $data = 'Zero','One','Two','Three'
PS> $data | ForEach-Object {"Item: [$PSItem]"}
Item: [Zero]
Item: [One]
Item: [Two]
Item: [Three]

Pokud jste předtím neviděli $PSItem, stačí vědět, že je to totéž jako $_. Můžete použít jeden z nich, protože oba představují aktuální objekt v kanálu.

Smyčka ForEach

Smyčka foreach funguje dobře s kolekcemi. Použití syntaxe: foreach ( <variable> in <collection> )

foreach ( $node in $data )
{
    "Item: [$node]"
}

Metoda ForEach

Mám tendenci zapomenout na tuto, ale funguje dobře pro jednoduché operace. PowerShell umožňuje volat ForEach() v kolekci.

PS> $data.ForEach({"Item [$PSItem]"})
Item [Zero]
Item [One]
Item [Two]
Item [Three]

ForEach() přebírá parametr, který je blokem skriptu. Závorky můžete vypustit a stačí zadat blok skriptu.

$data.ForEach{"Item [$PSItem]"}

Jedná se o méně známou syntaxi, ale funguje stejně. Tato metoda ForEach byla přidána v PowerShellu 4.0.

For smyčka

Smyčka for se hodně používá ve většině ostatních jazyků, ale v PowerShellu ji moc nevidíte. Když ho vidíte, často je to v kontextu procházení pole.

for ( $index = 0; $index -lt $data.Count; $index++)
{
    "Item: [{0}]" -f $data[$index]
}

První věc, kterou uděláme, je inicializovat $index na 0. Pak přidáme podmínku, že $index musí být menší než $data.Count. Nakonec určíme, že pokaždé, když opakujeme, musíme zvýšit index o 1. V tomto případě $index++ je zkratka pro $index = $index + 1. Operátor formátu (-f) slouží k vložení hodnoty $data[$index] do výstupního řetězce.

Kdykoli používáte smyčku for, věnujte zvláštní pozornost podmínce. Použil jsem $index -lt $data.Count tady. Je snadné, když se podmínka trochu špatně nastaví, což vede k chybě typu off-by-one v logice. Použití $index -le $data.Count nebo $index -lt ($data.Count - 1) je vždy trochu nesprávné. To by způsobilo, že váš výsledek zpracuje příliš mnoho nebo příliš málo položek. Jedná se o klasickou chybu typu off-by-one.

Přepínací smyčka

To je ten, který je snadno přehlédnutelný. Pokud zadáte pole příkazu switch, zkontroluje každou položku v poli.

$data = 'Zero','One','Two','Three'
switch( $data )
{
    'One'
    {
        'Tock'
    }
    'Three'
    {
        'Tock'
    }
    Default
    {
        'Tick'
    }
}
Tick
Tock
Tick
Tock

S příkazem switch můžeme dělat spoustu skvělých věcí. Mám další článek věnovaný tomuto.

Aktualizace hodnot

Pokud je pole kolekcí řetězců nebo celých čísel (hodnotových typů), někdy můžete chtít aktualizovat hodnoty v poli, jakmile je smyčte. Většina výše uvedených smyček používá proměnnou ve smyčce, která obsahuje kopii hodnoty. Pokud tuto proměnnou aktualizujete, původní hodnota v poli se neaktualizuje.

Výjimkou k tomuto tvrzení je smyčka for. Pokud chcete procházet pole a aktualizovat hodnoty uvnitř, pak smyčka for je to, co hledáte.

for ( $index = 0; $index -lt $data.Count; $index++ )
{
    $data[$index] = "Item: [{0}]" -f $data[$index]
}

Tento příklad vezme hodnotu podle indexu, provede několik změn a pak tento stejný index použije k jeho přiřazení zpět.

Pole objektů

Zatím jedinou věcí, kterou jsme umístili do pole, je typ hodnoty, ale pole můžou obsahovat i objekty.

$data = @(
    [pscustomobject]@{FirstName='Kevin';LastName='Marquette'}
    [pscustomobject]@{FirstName='John'; LastName='Doe'}
)

Mnoho rutin vrací kolekce objektů jako pole, když je přiřadíte proměnné.

$processList = Get-Process

Všechny základní funkce, o kterých jsme už mluvili, se stále vztahují na pole objektů s několika podrobnostmi, které stojí za zmínku.

Přístup k vlastnostem

Index můžeme použít pro přístup k jednotlivé položce v kolekci stejně jako u typů hodnot.

PS> $data[0]

FirstName LastName
-----     ----
Kevin     Marquette

K vlastnostem můžeme přistupovat a aktualizovat je přímo.

PS> $data[0].FirstName

Kevin

PS> $data[0].FirstName = 'Jay'
PS> $data[0]

FirstName LastName
-----     ----
Jay       Marquette

Vlastnosti pole

Pokud chcete získat přístup ke všem vlastnostem, obvykle byste museli vytvořit výčet celého seznamu, jako je tento:

PS> $data | ForEach-Object {$_.LastName}

Marquette
Doe

Nebo pomocí cmdletu Select-Object -ExpandProperty.

PS> $data | Select-Object -ExpandProperty LastName

Marquette
Doe

PowerShell nám nabízí možnost přímo požádat o LastName. PowerShell vytvoří výčet všech pro nás a vrátí čistý seznam.

PS> $data.LastName

Marquette
Doe

Výčet stále probíhá, ale nevidíme za ním složitost.

Filtrování Where-Object

To je místo, kde Where-Object přichází, abychom mohli filtrovat a vybírat, co chceme z pole na základě vlastností objektu.

PS> $data | Where-Object {$_.FirstName -eq 'Kevin'}

FirstName LastName
-----     ----
Kevin     Marquette

Můžeme napsat stejný dotaz, abychom získali FirstName, které hledáme.

$data | where FirstName -EQ Kevin

Where()

Pole mají Where() metodu, která umožňuje zadat scriptblock pro filtr.

$data.Where({$_.FirstName -eq 'Kevin'})

Tato funkce byla přidána v PowerShellu 4.0.

Aktualizace objektů ve smyčkách

U typů hodnot je jediným způsobem, jak pole aktualizovat, použít smyčku for, protože potřebujeme znát index, který nahradí hodnotu. S objekty máme více možností, protože se jedná o odkazové typy. Tady je rychlý příklad:

foreach($person in $data)
{
    $person.FirstName = 'Kevin'
}

Tato smyčka prochází všechny objekty v poli $data. Vzhledem k tomu, že objekty jsou odkazové typy, $person proměnná odkazuje na stejný objekt, který je v poli. Aktualizace vlastností tak aktualizují původní.

Tímto způsobem stále nemůžete nahradit celý objekt. Pokud se pokusíte přiřadit nový objekt k proměnné $person, aktualizujete odkaz proměnné na něco jiného, co už neukazuje na původní objekt v poli. To nefunguje tak, jak byste očekávali:

foreach($person in $data)
{
    $person = [pscustomobject]@{
        FirstName='Kevin'
        LastName='Marquette'
    }
}

Operátoři

Operátory v PowerShellu pracují také na polích. Některé z nich fungují trochu jinak.

-připojit

Operátor -join je nejzřejmější, takže se na něj podívejme nejdříve. Líbí se mi operátor -join a často ho používám. Spojí všechny prvky v poli se zadaným znakem nebo řetězcem.

PS> $data = @(1,2,3,4)
PS> $data -join '-'
1-2-3-4
PS> $data -join ','
1,2,3,4

Jednou z funkcí, které se mi líbí o operátoru -join, je, že zpracovává jednotlivé položky.

PS> 1 -join '-'
1

Používám to v rámci protokolování a podrobných zpráv.

PS> $data = @(1,2,3,4)
PS> "Data is $($data -join ',')."
Data is 1,2,3,4.

-join $array

Tady je chytrý trik, který mi Lee Dailey ukázal. Pokud byste někdy chtěli spojit všechno bez oddělovače, můžete místo toho udělat toto:

PS> $data = @(1,2,3,4)
PS> $data -join $null
1234

Můžete použít pole s parametrem -join bez předpony. Podívejte se na tento příklad a zjistěte, o čem mluvím.

PS> $data = @(1,2,3,4)
PS> -join $data
1234

-replace a -split

Ostatní operátory, jako jsou -replace a -split, se spouštějí u každé položky v poli. Nemůžu říct, že jsem je někdy použil tímto způsobem, ale tady je příklad.

PS> $data = @('ATX-SQL-01','ATX-SQL-02','ATX-SQL-03')
PS> $data -replace 'ATX','LAX'
LAX-SQL-01
LAX-SQL-02
LAX-SQL-03

-obsahuje

Operátor -contains umožňuje zkontrolovat matici hodnot a zjistit, jestli obsahuje zadanou hodnotu.

PS> $data = @('red','green','blue')
PS> $data -contains 'green'
True

-v

Pokud máte jednu hodnotu, kterou chcete ověřit, odpovídá jedné z několika hodnot, můžete použít operátor -in. Hodnota by byla na levé straně a pole na pravé straně operátoru.

PS> $data = @('red','green','blue')
PS> 'green' -in $data
True

To může být nákladné, pokud je seznam velký. Často používám vzor regulárních výrazů, pokud kontrolujem více než několik hodnot.

PS> $data = @('red','green','blue')
PS> $pattern = "^({0})$" -f ($data -join '|')
PS> $pattern
^(red|green|blue)$

PS> 'green' -match $pattern
True

-eq a -ne

Rovnost a pole můžou být komplikované. Když je pole na levé straně, porovná se každá položka. Místo vrácení Truevrátí objekt, který odpovídá.

PS> $data = @('red','green','blue')
PS> $data -eq 'green'
green

Když použijete operátor -ne, získáme všechny hodnoty, které se nerovnají naší hodnotě.

PS> $data = @('red','green','blue')
PS> $data -ne 'green'
red
blue

Pokud to použijete v příkazu if(), vrácená hodnota je hodnota True. Pokud se nevrátí žádná hodnota, jedná se o False hodnotu. Oba tyto další příkazy se vyhodnotí jako True.

$data = @('red','green','blue')
if ( $data -eq 'green' )
{
    'Green was found'
}
if ( $data -ne 'green' )
{
    'And green was not found'
}

Za chvíli se k tomu vrátím, až si promluvíme o testování na $null.

-utkání

Operátor -match se pokusí spárovat každou položku v kolekci.

PS> $servers = @(
    'LAX-SQL-01'
    'LAX-API-01'
    'ATX-SQL-01'
    'ATX-API-01'
)
PS> $servers -match 'SQL'
LAX-SQL-01
ATX-SQL-01

Když použijete -match s jednou hodnotou, naplní se speciální proměnná $Matches informacemi o shodě. To není případ, kdy se pole zpracuje tímto způsobem.

Můžeme použít stejný přístup s Select-String.

$servers | Select-String SQL

Podrobněji se podívám na Select-String,-match a $Matches proměnnou v jiném příspěvku nazvaném Mnoho způsobů použití regex.

$null nebo prázdné

Testování $null nebo prázdných polí může být složité. Tady jsou běžné pasti s poli.

Na první pohled toto stanovisko vypadá, jako by mělo fungovat.

if ( $array -eq $null)
{
    'Array is $null'
}

Ale právě jsem přešel, jak -eq kontroluje každou položku v poli. Můžeme mít pole s několika položkami a jednou hodnotou $null, které by se vyhodnotilo jako $true.

$array = @('one',$null,'three')
if ( $array -eq $null)
{
    'I think Array is $null, but I would be wrong'
}

Proto je osvědčeným postupem umístit $null na levou stranu operátoru. Díky tomu tento scénář není problém.

if ( $null -eq $array )
{
    'Array actually is $null'
}

Pole $null není totéž jako prázdné pole. Pokud víte, že máte pole, zkontrolujte počet objektů v něm. Pokud je pole $null, počet je 0.

if ( $array.Count -gt 0 )
{
    "Array isn't empty"
}

Je tu ještě jedna past, na kterou si musíte dávat pozor. Můžete použít Count i v případě, že máte jeden objekt, pokud tento objekt není PSCustomObject. Jedná se o chybu, která je opravená v PowerShellu 6.1. To je dobrá zpráva, ale mnoho lidí je pořád na verzi 5.1 a musí si na to dát pozor.

PS> $object = [pscustomobject]@{Name='TestObject'}
PS> $object.Count
$null

Pokud stále používáte PowerShell 5.1, můžete objekt zabalit do pole, než zkontrolujete počet, abyste získali přesný počet.

if ( @($array).Count -gt 0 )
{
    "Array isn't empty"
}

Pro jistotu zkontrolujte $nulla pak zkontrolujte počet.

if ( $null -ne $array -and @($array).Count -gt 0 )
{
    "Array isn't empty"
}

Všechny -eq

Nedávno jsem viděl někoho na Reddit zeptat se, jak ověřit, že každá hodnota v poli odpovídá dané hodnotě. Uživatel Reddit u/bis měl toto chytré řešení, které se zaměřuje na nesprávné hodnoty a obrátí výsledek.

$results = Test-Something
if ( -not ( $results -ne 'Passed') )
{
    'All results a Passed'
}

Přidání do polí

V tomto okamžiku začínáte přemýšlet o tom, jak přidat položky do pole. Rychlá odpověď je, že nemůžete. Pole má pevnou velikost v paměti. Pokud ho potřebujete zvětšit nebo do ní přidat jednu položku, musíte vytvořit nové pole a zkopírovat všechny hodnoty ze starého pole. To zní jako spousta práce, ale PowerShell skrývá složitost vytváření nového pole. PowerShell používá operátor sčítání (+) pro pole.

Poznámka:

PowerShell neimplementuje operaci odčítání. Pokud chcete flexibilní alternativu k poli, musíte použít obecný objekt List.

Přidání pole

K vytvoření nového pole můžeme použít operátor sčítání s poli. Takže vzhledem k těmto dvěma polím:

$first = @(
    'Zero'
    'One'
)
$second = @(
    'Two'
    'Three'
)

Můžeme je sečíst, abychom získali nové pole.

PS> $first + $second

Zero
One
Two
Three

Plus se rovná +=

Můžeme vytvořit nové pole a přidat do ní položku takto:

$data = @(
    'Zero'
    'One'
    'Two'
    'Three'
)
$data += 'four'

Nezapomeňte, že pokaždé, když použijete +=, že duplikujete a vytváříte nové pole. Nejedná se o problém u malých datových sad, ale velmi špatně se škáluje.

Přiřazení pipeline

Výsledky libovolného kanálu můžete přiřadit do proměnné. Jedná se o pole, pokud obsahuje více položek.

$array = 1..5 | ForEach-Object {
    "ATX-SQL-$PSItem"
}

Obvykle, když uvažujeme o použití pipeline, myslíme na typické jednořádkové příkazy PowerShellu. Můžeme využít kanál pomocí příkazů foreach() a dalších smyček. Takže místo přidávání položek do pole ve smyčce můžeme položky vložit do pipeline.

$array = foreach ( $node in (1..5))
{
    "ATX-SQL-$node"
}

Typy polí

Ve výchozím nastavení se pole v PowerShellu vytvoří jako typ [psobject[]]. To umožňuje, aby obsahoval jakýkoli typ objektu nebo hodnoty. To funguje, protože vše je zděděno z typu PSObject.

Pole se silným typováním

Pole libovolného typu můžete vytvořit pomocí podobné syntaxe. Když vytvoříte pole silného typu, může obsahovat pouze hodnoty nebo objekty zadaného typu.

PS> [int[]] $numbers = 1,2,3
PS> [int[]] $numbers2 = 'one','two','three'
ERROR: Cannot convert value "one" to type "System.Int32". Input string was not in a correct format."

PS> [string[]] $strings = 'one','two','three'

ArrayList

Přidání položek do pole je jedním z jeho největších omezení, ale existuje několik dalších kolekcí, které můžeme využít k vyřešení tohoto problému.

ArrayList je často jednou z prvních věcí, která nás napadne, když potřebujeme pole, s nímž lze pracovat rychleji. Funguje jako pole objektů, které potřebujeme, ale zpracovává rychlé přidávání položek.

Tady je postup, jak vytvoříme ArrayList a přidáme do něj položky.

$myarray = [System.Collections.ArrayList]::new()
[void]$myArray.Add('Value')

Využíváme .NET k získání tohoto typu. V tomto případě k jeho vytvoření používáme výchozí konstruktor. Potom zavoláme metodu Add, která do ní přidá položku.

Důvodem, proč používám [void] na začátku řádku je potlačení návratového kódu. Některá volání .NET to dělají a můžou vytvořit neočekávaný výstup.

Pokud jsou jedinými daty, která máte v poli, řetězce, pak se také podívejte na použití StringBuilder. Je to skoro stejná věc, ale má některé metody, které jsou jen pro práci s řetězci. StringBuilder je speciálně navržen pro výkon.

Často vídáme, jak se lidé přesouvají z polí do ArrayList. Ale pochází z doby, kdy jazyk C# neměl obecnou podporu. ArrayList je zastaralý ve prospěch obecného List[]

Obecný seznam

Obecný typ je speciální typ v jazyce C#, který definuje generalizovanou třídu a uživatel určuje datové typy, které používá při vytváření. Pokud tedy chcete seznam čísel nebo řetězců, nadefinujte, že chcete seznam typů int nebo string.

Zde je postup, jak vytvořit seznam pro řetězce.

$mylist = [System.Collections.Generic.List[string]]::new()

Nebo seznam čísel.

$mylist = [System.Collections.Generic.List[int]]::new()

Existující pole můžeme přetypovat na seznam podobný tomuto, aniž bychom nejprve vytvořili objekt:

$mylist = [System.Collections.Generic.List[int]]@(1,2,3)

Syntaxi můžeme zkrátit příkazem using namespace v PowerShellu 5 a novějším. Příkaz using musí být prvním řádkem skriptu. Když deklarujete obor názvů, PowerShell vám umožní vynechat jeho použití při odkazování na datové typy.

using namespace System.Collections.Generic
$myList = [List[int]]@(1,2,3)

Díky tomu je List mnohem použitelnější.

Máte k dispozici podobnou metodu Add. Na rozdíl od ArrayList není v metodě Add žádná návratová hodnota, takže ji nemusíme void.

$myList.Add(10)

A stále můžeme přistupovat k prvkům, jako jsou jiná pole.

PS> $myList[-1]
10

List[psobject]

Můžete mít seznam libovolného typu, ale pokud neznáte typ objektů, můžete je použít [List[psobject]] k jejich zahrnutí.

$list = [List[psobject]]::new()

Remove()

ArrayList i obecný List[] podporují odebrání položek z kolekce.

using namespace System.Collections.Generic
$myList = [List[string]]@('Zero','One','Two','Three')
[void]$myList.Remove("Two")
Zero
One
Three

Při práci s typy hodnot odebere první ze seznamu. Můžete ji znovu a znovu použít, abyste tuto hodnotu stále odstraňovali. Pokud máte odkazové typy, musíte zadat objekt, který chcete odebrat.

[List[System.Management.Automation.PSDriveInfo]]$drives = Get-PSDrive
$drives.Remove($drives[2])
$delete = $drives[2]
$drives.Remove($delete)

Metoda remove vrátí true, pokud byla schopna najít a odebrat položku z kolekce.

Další kolekce

Existuje mnoho dalších kolekcí, které lze použít, ale tyto jsou dobrá alternativa k obecným polím. Pokud se chcete dozvědět více o těchto možnostech, podívejte se na tento Gist, který Mark Kraus připravil.

Jiné drobné odlišnosti

Teď, když jsem probral všechny hlavní funkce, tady je několik dalších věcí, které jsem chtěl zmínit předtím, než jsem to zabalil.

Pole s pevnou velikostí

Zmínil jsem se, že po vytvoření pole nemůžete změnit jeho velikost. Pole předem určené velikosti můžeme vytvořit tak, že ho zavoláme pomocí konstruktoru new($size).

$data = [Object[]]::new(4)
$data.Count
4

Násobení polí

Zajímavým malým trikem je, že pole můžete vynásobit celým číslem.

PS> $data = @('red','green','blue')
PS> $data * 3
red
green
blue
red
green
blue
red
green
blue

Inicializace pomocí 0

Běžným scénářem je, že chcete vytvořit pole se všemi nulami. Pokud budete mít jenom celá čísla, pole celých čísel s pevným typem ve výchozím nastavení nastaví na všechny nuly.

PS> [int[]]::new(4)
0
0
0
0

Můžeme také použít násobicí trik k tomu.

PS> $data = @(0) * 4
PS> $data
0
0
0
0

Výhodou triku s násobením je, že můžete použít libovolnou hodnotu. Takže pokud byste raději jako výchozí hodnotu měli 255, bylo by to dobrý způsob, jak to udělat.

PS> $data = @(255) * 4
PS> $data
255
255
255
255

Vnořené pole

Pole uvnitř pole se nazývá vnořené pole. V PowerShellu je moc nepoužívám, ale použil jsem je více v jiných jazycích. Zvažte použití pole polí, když se vaše data hodí do mřížkového vzoru.

Tady jsou dva způsoby, jak můžeme vytvořit dvojrozměrné pole.

$data = @(@(1,2,3),@(4,5,6),@(7,8,9))

$data2 = @(
    @(1,2,3),
    @(4,5,6),
    @(7,8,9)
)

Čárka je v těchto příkladech velmi důležitá. Uvedl jsem dřívější příklad normálního pole na více řádcích, kde byla čárka nepovinná. To není případ s multidimenzionálním polem.

Způsob, jakým používáme zápis indexu, se mírně změní, když máme vnořené pole. Při použití výše uvedeného $data bychom získali přístup k hodnotě 3.

PS> $outside = 0
PS> $inside = 2
PS> $data[$outside][$inside]
3

Přidejte sadu hranatých závorek pro každou úroveň vnoření pole. První sada hranatých závorek je určená pro nejvzdálenější pole a pak pracujete směrem dovnitř.

Write-Output -NoEnumerate

PowerShell rád rozbalovat a vypisovat pole. Jedná se o základní aspekt toho, jak PowerShell používá kanál, ale někdy nechcete, aby se to stalo.

Běžně přesměrovávám objekty do Get-Member, abych se o nich dozvěděl víc. Když předám pole, dojde k jeho rozbalování a Get-Member uvidí členy pole, nikoli skutečné pole.

PS> $data = @('red','green','blue')
PS> $data | Get-Member
TypeName: System.String
...

Chcete-li zabránit rozbalení pole, můžete použít Write-Output -NoEnumerate.

PS> Write-Output -NoEnumerate $data | Get-Member
TypeName: System.Object[]
...

Mám druhý způsob, který je spíše vychytávka (a snažím se vyhnout vychytávkám, jako je tato). Před polem můžete umístit čárku. To zabalí $data do jiného pole, kde je jediným prvkem, takže po rozbalení vnějšího pole získáme zpět $data rozbalený.

PS> ,$data | Get-Member
TypeName: System.Object[]
...

Vrátit pole

K tomuto rozbalování polí dochází také při výstupu nebo vrácení hodnot z funkce. Pokud přiřadíte výstup proměnné, stále můžete získat pole, takže to obvykle není problém.

Háček je v tom, že máte nové pole. Pokud se jedná o problém, můžete ho obejít pomocí Write-Output -NoEnumerate $array nebo return ,$array.

Cokoli jiného?

Vím, že je toho hodně k pochopení. Doufám, že se pokaždé, když tento článek čtete, něco naučíte a že se pro vás stane dobrým odkazem na dlouhou dobu. Pokud jste zjistili, že to může být užitečné, sdílejte ho s ostatními, o které si myslíte, že z toho může získat hodnotu.

Odsud bych vám doporučil podívat se na podobný příspěvek, který jsem napsal o hashtables.