Dela via


Allt du ville veta om matriser

Matriser är en grundläggande språkfunktion i de flesta programmeringsspråk. De är en samling värden eller objekt som är svåra att undvika. Låt oss ta en närmare titt på matriser och allt de har att erbjuda.

Kommentar

Den ursprungliga versionen av den här artikeln visades på bloggen skriven av @KevinMarquette. PowerShell-teamet tackar Kevin för att ha delat det här innehållet med oss. Kolla in hans blogg på PowerShellExplained.com.

Vad är en matris?

Jag börjar med en grundläggande teknisk beskrivning av vilka matriser som är och hur de används av de flesta programmeringsspråk innan jag övergår till andra sätt som PowerShell använder dem på.

En matris är en datastruktur som fungerar som en samling med flera objekt. Du kan iterera över matrisen eller komma åt enskilda objekt med hjälp av ett index. Matrisen skapas som ett sekventiellt minnessegment där varje värde lagras bredvid det andra.

Jag kommer att beröra var och en av dessa detaljer när vi går.

Grundläggande användning

Eftersom matriser är en sådan grundläggande funktion i PowerShell finns det en enkel syntax för att arbeta med dem i PowerShell.

Skapa en matris

En tom matris kan skapas med hjälp av @()

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

Vi kan skapa en matris och seeda den med värden bara genom att placera dem i @() parenteserna.

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

PS> $data
Zero
One
Two
Three

Den här matrisen har 4 objekt. När vi anropar variabeln $data ser vi listan över våra objekt. Om det är en matris med strängar får vi en rad per sträng.

Vi kan deklarera en matris på flera rader. Kommatecknet är valfritt i det här fallet och utelämnas vanligtvis.

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

Jag föredrar att deklarera mina matriser på flera rader på det viset. Det blir inte bara lättare att läsa när du har flera objekt, det gör det också lättare att jämföra med tidigare versioner när du använder källkontroll.

Annan syntax

Det är vanligt att det är syntaxen för att @() skapa en matris, men kommaavgränsade listor fungerar för det mesta.

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

Skrivutdata för att skapa matriser

Ett coolt litet trick värt att nämna är att du kan använda Write-Output för att snabbt skapa strängar i konsolen.

$data = Write-Output Zero One Two Three

Det här är praktiskt eftersom du inte behöver placera citattecken runt strängarna när parametern accepterar strängar. Jag skulle aldrig göra detta i ett skript men det är rättvist spel i konsolen.

Åtkomst till objekt

Nu när du har en matris med objekt i den kanske du vill komma åt och uppdatera dessa objekt.

Förskjutning

För att få åtkomst till enskilda objekt använder vi hakparenteserna med ett förskjutningsvärde [] från och med 0. Så här hämtar vi det första objektet i matrisen:

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

Anledningen till att vi använder noll här är att det första objektet är i början av listan så vi använder en förskjutning på 0 objekt för att komma åt det. För att komma till det andra objektet skulle vi behöva använda en förskjutning på 1 för att hoppa över det första objektet.

PS> $data[1]
One

Det innebär att det sista objektet är vid förskjutning 3.

PS> $data[3]
Three

Index

Nu kan du se varför jag valde de värden som jag gjorde för det här exemplet. Jag introducerade detta som en förskjutning eftersom det är vad det verkligen är, men denna förskjutning kallas oftare för ett index. Ett index som börjar på 0. För resten av den här artikeln kommer jag att kalla förskjutningen ett index.

Särskilda indextrick

På de flesta språk kan du bara ange ett enda tal som index och du får tillbaka ett enda objekt. PowerShell är mycket mer flexibelt. Du kan använda flera index samtidigt. Genom att ange en lista över index kan vi välja flera objekt.

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

Objekten returneras baserat på ordningen på de angivna indexen. Om du duplicerar ett index får du objektet båda gångerna.

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

Vi kan ange en sekvens med tal med den inbyggda .. operatorn.

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

Detta fungerar också omvänt.

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

Du kan använda negativa indexvärden för att förskjuta från slutet. Om du behöver det sista objektet i listan kan du använda -1.

PS> $data[-1]
Three

Ett varningens ord här med operatorn .. . Sekvensen 0..-1 och -1..0 utvärdera till värdena 0,-1 och -1,0. Det är lätt att se $data[0..-1] och tro att det skulle räkna upp alla objekt om du glömmer den här informationen. $data[0..-1] ger dig samma värde som $data[0,-1] genom att ge dig det första och sista objektet i matrisen (och inget av de andra värdena). Här är ett större exempel:

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

Detta är samma som:

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

Utanför gränserna

På de flesta språk får du någon typ av fel eller ett undantag om du försöker komma åt ett index för ett objekt som ligger efter matrisens slut. PowerShell returnerar ingenting i tyst.

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

Det går inte att indexera till en null-matris

Om variabeln är $null och du försöker indexera den som en matris får du ett System.Management.Automation.RuntimeException undantag med meddelandet Cannot index into a null array.

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

Kontrollera därför att dina matriser inte $null är det innan du försöker komma åt elementen i dem.

Antal

Matriser och andra samlingar har en count-egenskap som anger hur många objekt som finns i matrisen.

PS> $data.count
4

PowerShell 3.0 har lagt till en count-egenskap i de flesta objekt. du kan ha ett enda objekt och det bör ge dig ett antal 1.

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

Även $null har en count-egenskap förutom att den returnerar 0.

PS> $null.count
0

Det finns några traps här som jag kommer att återkomma när jag täcker söka $null efter eller tomma matriser senare i den här artikeln.

Off-by-one-fel

Ett vanligt programmeringsfel skapas eftersom matriser börjar vid index 0. Off-by-one-fel kan introduceras på två sätt.

Den första är genom att mentalt tro att du vill ha det andra objektet och använda ett index för 2 och verkligen få det tredje objektet. Eller genom att tro att du har fyra objekt och vill ha det sista objektet, så du använder antalet för att komma åt det sista objektet.

$data[ $data.count ]

PowerShell låter dig gärna göra det och ge dig exakt vilket objekt som finns på index 4: $null. Du bör använda $data.count - 1 eller -1 som vi har lärt oss om ovan.

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

Det är här du kan använda indexet -1 för att hämta det sista elementet.

PS> $data[ -1 ]
Three

Lee Dailey påpekade också för mig att vi kan använda $data.GetUpperBound(0) för att få det maximala indexnumret.

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

Det näst vanligaste sättet är när du itererar listan och inte slutar vid rätt tidpunkt. Jag återkommer när vi pratar om att använda loopen for .

Uppdatera objekt

Vi kan använda samma index för att uppdatera befintliga objekt i matrisen. Detta ger oss direkt åtkomst till att uppdatera enskilda objekt.

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

Om vi försöker uppdatera ett objekt som är förbi det sista elementet får vi ett Index was outside the bounds of the array. fel.

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

Jag återkommer senare när jag pratar om hur man gör en matris större.

Iteration

Vid något tillfälle kan du behöva gå igenom eller iterera hela listan och utföra vissa åtgärder för varje objekt i matrisen.

Pipeline

Matriser och PowerShell-pipelinen är avsedda för varandra. Detta är ett av de enklaste sätten att bearbeta dessa värden på. När du skickar en matris till en pipeline bearbetas varje objekt i matrisen individuellt.

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

Om du inte har sett $PSItem förut, bara vet att det är samma sak som $_. Du kan använda någon av dem eftersom båda representerar det aktuella objektet i pipelinen.

ForEach-loop

Loopen ForEach fungerar bra med samlingar. Med hjälp av syntaxen: foreach ( <variable> in <collection> )

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

ForEach-metod

Jag tenderar att glömma den här men det fungerar bra för enkla operationer. Med PowerShell kan du anropa .ForEach() en samling.

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

Tar .foreach() en parameter som är ett skriptblock. Du kan släppa parenteserna och bara ange skriptblocket.

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

Det här är en mindre känd syntax, men den fungerar på samma sätt. Den här foreach metoden lades till i PowerShell 4.0.

For-loop

Loopen for används mycket på de flesta andra språk, men du ser den inte så mycket i PowerShell. När du ser det är det ofta i samband med att du går i en matris.

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

Det första vi gör är att initiera en $index till 0. Sedan lägger vi till villkoret som $index måste vara mindre än $data.count. Slutligen anger vi att varje gång vi loopar måste vi öka indexet 1med . I det här fallet $index++ är det en förkortning för $index = $index + 1. Formatoperatorn (-f) används för att infoga värdet $data[$index] för i utdatasträngen.

Var särskilt uppmärksam på villkoret när du använder en for loop. Jag använde $index -lt $data.count här. Det är lätt att få villkoret något fel för att få ett fel i logiken. Använda $index -le $data.count eller $index -lt ($data.count - 1) är någonsin så lite fel. Det skulle göra att resultatet bearbetas för många eller för få objekt. Det här är det klassiska off-by-one-felet.

Switch-loop

Detta är en som är lätt att förbise. Om du anger en matris till en switch-instruktion kontrollerar den varje objekt i matrisen.

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

Det finns många coola saker som vi kan göra med switch-instruktionen. Jag har en annan artikel tillägnad detta.

Uppdatera värden

När matrisen är en samling sträng- eller heltal (värdetyper) kanske du ibland vill uppdatera värdena i matrisen när du loopar över dem. De flesta av looparna ovan använder en variabel i loopen som innehåller en kopia av värdet. Om du uppdaterar variabeln uppdateras inte det ursprungliga värdet i matrisen.

Undantaget till den instruktionen är loopen for . Om du vill gå igenom en matris och uppdatera värden i den är loopen for det du letar efter.

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

Det här exemplet tar ett värde efter index, gör några ändringar och använder sedan samma index för att tilldela tillbaka det.

Matriser med objekt

Hittills är det enda vi har placerat i en matris en värdetyp, men matriser kan också innehålla objekt.

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

Många cmdletar returnerar samlingar av objekt som matriser när du tilldelar dem till en variabel.

$processList = Get-Process

Alla grundläggande funktioner som vi redan har pratat om gäller fortfarande för matriser med objekt med några få detaljer som är värda att påpeka.

Åtkomst till egenskaper

Vi kan använda ett index för att komma åt ett enskilt objekt i en samling precis som med värdetyper.

PS> $data[0]

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

Vi kan komma åt och uppdatera egenskaper direkt.

PS> $data[0].FirstName

Kevin

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

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

Matrisegenskaper

Normalt skulle du behöva räkna upp hela listan så här för att få åtkomst till alla egenskaper:

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

Marquette
Doe

Eller genom att använda cmdleten Select-Object -ExpandProperty .

PS> $data | Select-Object -ExpandProperty LastName

Marquette
Doe

Men PowerShell ger oss möjlighet att begära LastName direkt. PowerShell räknar upp dem alla åt oss och returnerar en ren lista.

PS> $data.LastName

Marquette
Doe

Uppräkningen sker fortfarande, men vi ser inte komplexiteten bakom den.

Where-Object-filtrering

Det är här som Where-Object vi kommer in så att vi kan filtrera och välja vad vi vill ha ut av matrisen baserat på objektets egenskaper.

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

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

Vi kan skriva samma fråga för att hämta den FirstName vi letar efter.

$data | Where FirstName -eq Kevin

Where()

Matriser har en Where() metod på sig som gör att du kan ange en scriptblock för filtret.

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

Den här funktionen har lagts till i PowerShell 4.0.

Uppdatera objekt i loopar

Med värdetyper är det enda sättet att uppdatera matrisen att använda en for-loop eftersom vi behöver känna till indexet för att ersätta värdet. Vi har fler alternativ med objekt eftersom de är referenstyper. Här är ett snabbt exempel:

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

Den här loopen går igenom alla objekt i matrisen $data . Eftersom objekt är referenstyper refererar variabeln $person till exakt samma objekt som finns i matrisen. Så uppdateringar av dess egenskaper uppdaterar originalet.

Du kan fortfarande inte ersätta hela objektet på det här sättet. Om du försöker tilldela variabeln $person ett nytt objekt uppdaterar du variabelreferensen till något annat som inte längre pekar på det ursprungliga objektet i matrisen. Detta fungerar inte som förväntat:

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

Operatorer

Operatorerna i PowerShell fungerar också på matriser. Vissa av dem fungerar lite annorlunda.

-ansluta

Operatorn -join är den mest uppenbara, så låt oss titta på den först. Jag gillar operatorn -join och använder den ofta. Den sammanfogar alla element i matrisen med det tecken eller den sträng som du anger.

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

En av de funktioner som jag gillar med operatorn är att den -join hanterar enskilda objekt.

PS> 1 -join '-'
1

Jag använder detta i loggning och utförliga meddelanden.

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

-join $array

Här är ett smart trick som Lee Dailey påpekade för mig. Om du någonsin vill ansluta allt utan avgränsare, i stället för att göra detta:

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

Du kan använda -join med matrisen som parameter utan prefix. Ta en titt på det här exemplet för att se att jag pratar om.

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

-replace och -split

De andra operatorerna gillar -replace och -split kör på varje objekt i matrisen. Jag kan inte säga att jag någonsin har använt dem på det här sättet men här är ett exempel.

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

-Innehåller

Med -contains operatorn kan du kontrollera en matris med värden för att se om den innehåller ett angivet värde.

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

-i

När du har ett enda värde som du vill verifiera matchar ett av flera värden kan du använda operatorn -in . Värdet skulle finnas till vänster och matrisen till höger om operatorn.

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

Detta kan bli dyrt om listan är stor. Jag använder ofta ett regex-mönster om jag kontrollerar mer än några värden.

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

PS> 'green' -match $pattern
True

-eq och -ne

Likhet och matriser kan bli komplicerade. När matrisen finns till vänster jämförs varje objekt. I stället för att Truereturnera returnerar det objektet som matchar.

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

När du använder operatorn -ne får vi alla värden som inte är lika med vårt värde.

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

När du använder detta i en if() -instruktion är ett värde som returneras ett True värde. Om inget värde returneras är det ett False värde. Båda dessa nästa instruktioner utvärderas till True.

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

Jag återkommer till detta om en stund när vi pratar om testning för $null.

-tändsticka

Operatorn -match försöker matcha varje objekt i samlingen.

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

När du använder -match med ett enda värde fylls en särskild variabel $Matches i med matchningsinformation. Så är inte fallet när en matris bearbetas på det här sättet.

Vi kan använda samma metod med Select-String.

$servers | Select-String SQL

Jag tar en närmare titt på Select-String,-match och variabeln $matches i ett annat inlägg som heter De många sätten att använda regex.

$null eller tom

Det kan vara svårt att testa för $null eller tomma matriser. Här är de vanliga trapserna med matriser.

I korthet ser den här instruktionen ut att fungera.

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

Men jag gick bara igenom hur -eq kontrollerar varje objekt i matrisen. Så vi kan ha en matris med flera objekt med ett enda $null värde och det skulle utvärderas till $true

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

Därför är det en bra idé att placera operatorn $null till vänster. Detta gör det här scenariot till ett icke-problem.

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

En $null matris är inte samma sak som en tom matris. Om du vet att du har en matris kontrollerar du antalet objekt i den. Om matrisen är $nullär 0antalet .

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

Det finns en fälla till att se upp för här. Du kan använda count även om du har ett enda objekt, såvida inte det objektet är en PSCustomObject. Det här är en bugg som har åtgärdats i PowerShell 6.1. Det är goda nyheter, men många människor är fortfarande på 5.1 och måste se upp för det.

PS> $object = [PSCustomObject]@{Name='TestObject'}
PS> $object.count
$null

Om du fortfarande använder PowerShell 5.1 kan du omsluta objektet i en matris innan du kontrollerar antalet för att få ett korrekt antal.

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

Om du vill spela upp det på ett säkert sätt kontrollerar du $nullantalet.

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

Alla -eq

Jag såg nyligen någon på Reddit fråga hur man verifierar att varje värde i en matris matchar ett visst värde. Reddit-användaren u/bis hade den här smarta lösningen som söker efter felaktiga värden och sedan vänder resultatet.

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

Lägga till i matriser

Nu börjar du undra hur du lägger till objekt i en matris. Det snabba svaret är att du inte kan det. En matris är en fast storlek i minnet. Om du behöver utöka det eller lägga till ett enda objekt i det måste du skapa en ny matris och kopiera alla värden från den gamla matrisen. Det här låter som mycket arbete, men PowerShell döljer komplexiteten i att skapa den nya matrisen. PowerShell implementerar additionsoperatorn (+) för matriser.

Kommentar

PowerShell implementerar inte någon subtraktion. Om du vill ha ett flexibelt alternativ till en matris måste du använda ett allmänt List objekt.

Matristillägg

Vi kan använda additionsoperatorn med matriser för att skapa en ny matris. Så med tanke på dessa två matriser:

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

Vi kan lägga till dem tillsammans för att hämta en ny matris.

PS> $first + $second

Zero
One
Two
Three

Plus är lika med +=

Vi kan skapa en ny matris på plats och lägga till ett objekt i den så här:

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

Kom bara ihåg att varje gång du använder += det duplicerar och skapar du en ny matris. Detta är inte ett problem för små datauppsättningar, men det skalas extremt dåligt.

Pipelinetilldelning

Du kan tilldela resultatet av valfri pipeline till en variabel. Det är en matris om den innehåller flera objekt.

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

Normalt när vi tänker på att använda pipelinen tänker vi på de typiska PowerShell-one-liners. Vi kan använda pipelinen med foreach() instruktioner och andra loopar. Så i stället för att lägga till objekt i en matris i en loop kan vi släppa objekt till pipelinen.

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

Matristyper

Som standard skapas en matris i PowerShell som en [PSObject[]] typ. På så sätt kan den innehålla alla typer av objekt eller värden. Detta fungerar eftersom allt ärvs från PSObject typen .

Starkt inskrivna matriser

Du kan skapa en matris av vilken typ som helst med en liknande syntax. När du skapar en starkt skriven matris kan den bara innehålla värden eller objekt av den angivna typen.

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

Att lägga till objekt i en matris är en av de största begränsningarna, men det finns några andra samlingar som vi kan vända oss till som löser det här problemet.

ArrayList Är ofta en av de första saker som vi tänker på när vi behöver en matris som är snabbare att arbeta med. Den fungerar som en objektmatris varje plats där vi behöver den, men den hanterar att lägga till objekt snabbt.

Så här skapar ArrayList och lägger vi till objekt i den.

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

Vi anropar till .NET för att hämta den här typen. I det här fallet använder vi standardkonstruktorn för att skapa den. Sedan anropar Add vi metoden för att lägga till ett objekt i den.

Anledningen till att jag använder [void] i början av raden är att utelämna returkoden. Vissa .NET-anrop gör detta och kan skapa oväntade utdata.

Om de enda data som du har i matrisen är strängar kan du också ta en titt på hur du använder StringBuilder. Det är nästan samma sak men har vissa metoder som bara är för att hantera strängar. Är StringBuilder speciellt utformad för prestanda.

Det är vanligt att se personer flytta till ArrayList från matriser. Men det kommer från en tid då C# inte hade allmänt stöd. ArrayList Är inaktuellt i stöd för den generiskaList[]

Allmän lista

En allmän typ är en särskild typ i C# som definierar en generaliserad klass och användaren anger de datatyper som används när den skapas. Så om du vill ha en lista med tal eller strängar definierar du att du vill ha int en lista över eller string typer.

Så här skapar du en lista för strängar.

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

Eller en lista för tal.

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

Vi kan omvandla en befintlig matris till en lista som den här utan att först skapa objektet:

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

Vi kan förkorta syntaxen med -instruktionen using namespace i PowerShell 5 och senare. -instruktionen using måste vara den första raden i skriptet. Genom att deklarera ett namnområde låter PowerShell dig lämna det utanför datatyperna när du refererar till dem.

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

Detta gör det List mycket mer användbart.

Du har en liknande Add metod tillgänglig för dig. Till skillnad från ArrayList finns det inget returvärde för Add metoden så vi behöver det inte void .

$myList.Add(10)

Och vi kan fortfarande komma åt elementen som andra matriser.

PS> $myList[-1]
10

Lista[PSObject]

Du kan ha en lista av vilken typ som helst, men när du inte känner till typen av objekt kan du använda [List[PSObject]] för att innehålla dem.

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

Remove()

Både ArrayList och har List[] stöd för att ta bort objekt från samlingen.

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

När du arbetar med värdetyper tar den bort den första från listan. Du kan anropa det om och om igen för att fortsätta ta bort det värdet. Om du har referenstyper måste du ange det objekt som du vill ta bort.

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

Metoden remove returnerar true om den kunde hitta och ta bort objektet från samlingen.

Fler samlingar

Det finns många andra samlingar som kan användas, men det här är de bra generiska matrisersättningarna. Om du är intresserad av att lära dig mer om fler av dessa alternativ kan du ta en titt på den här Gist som Mark Kraus satte ihop.

Andra nyanser

Nu när jag har täckt alla de stora funktionerna, här är några fler saker som jag ville nämna innan jag avslutar detta.

Förstorade matriser

Jag nämnde att du inte kan ändra storleken på en matris när den har skapats. Vi kan skapa en matris med en fördefinierad storlek genom att anropa den new($size) med konstruktorn.

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

Multiplicera matriser

Ett intressant litet trick är att du kan multiplicera en matris med ett heltal.

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

Initiera med 0

Ett vanligt scenario är att du vill skapa en matris med alla nollor. Om du bara ska ha heltal, är en starkt typbaserad matris med heltal standard för alla nollor.

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

Vi kan använda multiplikationstricket för att göra detta också.

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

Det fina med multiplikationstricket är att du kan använda valfritt värde. Så om du hellre vill ha 255 som standardvärde skulle det vara ett bra sätt att göra det.

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

Kapslade matriser

En matris i en matris kallas för en kapslad matris. Jag använder inte så mycket i PowerShell men jag har använt dem mer på andra språk. Överväg att använda en matris med matriser när dina data passar i ett rutnät som ett mönster.

Här är två sätt att skapa en tvådimensionell matris.

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

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

Kommatecknet är mycket viktigt i dessa exempel. Jag gav ett tidigare exempel på en normal matris på flera rader där kommatecknet var valfritt. Så är inte fallet med en flerdimensionell matris.

Sättet vi använder indexet på ändras något nu när vi har en kapslad matris. Med hjälp av $data ovanstående kommer vi åt värdet 3 på det här viset.

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

Lägg till en uppsättning hakparenteser för varje nivå av matriskapsling. Den första uppsättningen hakparenteser är för den yttre mest matrisen och sedan arbetar du dig in därifrån.

Write-Output -NoEnumerate

PowerShell gillar att packa upp eller räkna upp matriser. Det här är en viktig aspekt av hur PowerShell använder pipelinen, men det finns tillfällen då du inte vill att det ska hända.

Jag rör ofta objekt för att Get-Member lära mig mer om dem. När jag rör en matris till den packas den upp och Get-Member ser matrisens medlemmar och inte den faktiska matrisen.

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

Om du vill förhindra att matrisen skrivs ut kan du använda Write-Output -NoEnumerate.

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

Jag har ett andra sätt som är mer av ett hack (och jag försöker undvika hack så här). Du kan placera ett kommatecken framför matrisen innan du rör det. Detta omsluts $data till en annan matris där det är det enda elementet, så efter att den yttre matrisen har packats upp igen får vi tillbaka $data den.

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

Returnera en matris

Den här uppskrivningen av matriser sker också när du matar ut eller returnerar värden från en funktion. Du kan fortfarande hämta en matris om du tilldelar utdata till en variabel, så det är inte ofta ett problem.

Fångsten är att du har en ny matris. Om det någonsin är ett problem kan du använda Write-Output -NoEnumerate $array eller return ,$array för att kringgå det.

Något mer?

Jag vet att det här är mycket att ta in. Min förhoppning är att du lär dig något från den här artikeln varje gång du läser den och att det visar sig vara en bra referens för dig under en lång tid framöver. Om du tycker att det här är användbart kan du dela det med andra som du tror kan få ut värdet av det.

Härifrån rekommenderar jag att du kolla in ett liknande inlägg som jag skrev om hashtables.