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 1
med . 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 True
returnera 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 0
antalet .
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 $null
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.
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.