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 undersöka matriser närmare och se allt som de erbjuder.

Anmärkning

Den ursprungliga versionen av den här artikeln publicerades på bloggen som skrevs 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 array?

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 fortsätter.

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 allmänt känt att @() är syntaxen för att skapa en matris, men kommaseparerade listor fungerar för det mesta.

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

Write-Output 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 okej 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.

Kompensation

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 på position 3.

PS> $data[3]
Three

Innehållsförteckning

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

Särskilda indexknep

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ärderas 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 inget utan att ge något meddelande.

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.

Räkna

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 fällor här som jag kommer att återkomma till när jag talar om att söka efter $null eller tomma matriser senare i denna artikel.

Felaktig räkning med en enhet

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

Det första sättet är att mentalt tänka att du vill ha det andra föremålet och använda ett index som 2 för att verkligen få det tredje föremålet. 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.

Upprepning

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.

Rörledning

Matriser och PowerShell-pipelinen är ämnade 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 en samling med ForEach().

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

Det ForEach() tar 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.

För 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 iterera över 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 göra ett litet misstag i villkoret som leder till ett "off-by-one"-fel i logiken. Att använda $index -le $data.Count eller $index -lt ($data.Count - 1) är aningen fel. Det skulle leda till att ditt resultat bearbetar för många eller för få saker. Det här är det klassiska off-by-one-felet.

Switchslinga

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

Array-egenskaper

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 Where-Object kommer in så att vi kan filtrera och välja vad vi vill ha ut av arrayen 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

Var()

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'
    }
}

Operatörer

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 vad jag pratar om.

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

-ersätt och -split

De andra operatorerna som -replace och -split exekverar 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 ska vara till vänster och arrayen 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 uttryck 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.

-match

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 fallgroparna med matriser.

Vid första anblick verkar det här påståendet 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 bästa praxis att placera $null till vänster om operatorn. 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 antalet 0.

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"
}

För att spela helt säkert, kontrollera $null och kontrollera sedan antalet.

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.

Anmärkning

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.

Array-tillä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 addera dem för att få 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 += duplicerar du och skapar en ny matris. Detta är inte ett problem för små datauppsättningar, men det skalas extremt dåligt.

Pipeline-tilldelning

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 vi en ArrayList och lägger till objekt i den.

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

Vi anropar .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 endast används för att hantera strängar. Den StringBuilder är 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 föråldrad i stöd för den generiska List[]

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 en lista av typen int eller string.

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

Ta bort()

Både ArrayList och den generiska List[] har 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 kollektioner som kan användas, men det här är de goda generiska array-ersä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ördefinierade 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 använda konstruktorn new($size).

$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 av matriser när din data passar i ett rutnät.

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 yttersta matrisen och sedan arbetar du dig inåt 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 skickar ofta objekt till Get-Member för att lära mig mer om dem. När jag skicka 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 öppnas 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 skickar det vidare. Detta omsluter $data i en annan matris där det är det enda elementet, så när den yttre matrisen packas upp får vi tillbaka $data utan omslag.

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

Returnera en matris

Den här uppackningen 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.