共用方式為


您想要知道陣列的一切

陣列 是大部分程式設計語言的基本語言功能。 它們是難以避免的值或物件的集合。 讓我們仔細看看陣列及其提供的所有功能。

備註

本文的原始版本出現在@KevinMarquette撰寫的部落格上。 PowerShell 小組感謝 Kevin 與我們分享此內容。 請在 PowerShellExplained.com查看他的部落格。

什麼是陣列?

我將從基本的技術描述開始,說明什麼是陣列,以及大部分程式語言如何使用它們,接著再談談 PowerShell 使用它們的其他方式。

陣列是一種數據結構,可作為多個專案的集合。 您可以使用索引逐一查看陣列或存取個別專案。 陣列會建立為連續的記憶體區塊,其中每個值都會儲存在另一個值旁邊。

隨著我們的進展,我會討論每一個細節。

基本用法

因為陣列是 PowerShell 的基本功能,所以在 PowerShell 中使用它們有一種簡單的語法。

建立陣列

您可以使用 @() 建立空陣列

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

我們可以通過將數值放入 @() 括號中來初始化陣列。

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

PS> $data
Zero
One
Two
Three

此陣列有4個項目。 當我們呼叫 $data 變數時,會看到專案清單。 如果是字串陣列,則我們會為每個字串取得一行。

我們可以在多行上宣告陣列。 在此案例中,逗號是選擇性的,通常會被排除在外。

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

我偏好在多行上宣告陣列,如下所示。 當您有多個專案時,它不僅更容易閱讀,也可讓您在使用原始檔控制時更輕鬆地與舊版進行比較。

其他語法

通常,人們都知道 @() 是用來建立陣列的語法,但逗號分隔的清單通常情況下都能運行良好。

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

建立陣列的 Write-Output

值得一提的一個很酷的小技巧是,您可以使用 Write-Output 在控制台快速建立字串。

$data = Write-Output Zero One Two Three

這很方便,因為當參數接受字串時,您不需要在字串周圍加上引號。 我永遠不會在腳本中這樣做,但在主控台中是可以接受的。

存取項目

現在您有一個包含項目的陣列,您可能想要訪問和更新這些項目。

Offset

若要存取個別項目,我們會使用括弧 [],其位移值從 0 開始。 這就是我們在陣列中取得第一個項目的方式:

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

我們在這裡使用零的原因是因為第一個項目位於清單開頭,所以我們用 0 個項目的位移去取得它。 若要到達第二個項目,我們需要使用位移 1 來略過第一個項目。

PS> $data[1]
One

這表示最後一個項目位於偏移量第 3。

PS> $data[3]
Three

索引

現在,您可以看到為什麼我挑選了我為此範例所做的值。 我將這個介紹為偏移,因為這就是它真正的名稱,但這個偏移通常稱為索引。 從 0開始的索引。 在本文的其餘部分,我將稱位移為索引。

特殊索引技巧

在大部分的語言中,您只能指定單一數字作為索引,而您會得到單一項目。 PowerShell 更有彈性。 您可以使用多個索引。 藉由提供索引清單,我們可以選取數個項目。

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

項目會根據提供的索引順序傳回。 如果您複製索引,則會多次取得該項目。

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

我們可以使用內建 .. 運算符來指定數位序列。

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

這也在反向運作。

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

您可以使用負索引值從末端位移。 因此,如果您需要列表中的最後一個項目,您可以使用 -1

PS> $data[-1]
Three

在此使用 .. 運算子時需注意的一點。 序列 0..-1-1..0 評估結果為 0,-1-1,0的值。 很容易看到 $data[0..-1] 並認為它會列出所有項目,尤其是在您忽略此細節的情況下。 $data[0..-1] 提供與 $data[0,-1] 相同的值,取自陣列中的第一個和最後一個項目(不包括其他值)。 以下是較大的範例:

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

這與以下相同:

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

超出範圍

在大部分語言中,如果您嘗試存取超過陣列末尾的索引,會發生某種類型的錯誤或例外。 PowerShell 會毫無提示地不傳回任何內容。

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

無法對空陣列進行索引

如果您的變數是 $null,而您嘗試將其作為陣列進行索引,則會發生 System.Management.Automation.RuntimeException 例外狀況,並顯示訊息 Cannot index into a null array

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

因此,在您嘗試存取這些陣列內的元素之前,請先確定您的陣列不是 $null

計數

陣列和其他集合具有 Count 屬性,告訴您陣列中的項目數目。

PS> $data.Count
4

PowerShell 3.0 已將 Count 屬性新增至大多數物件。 您可以有單一物件,而且它應該會給您一個1的數量。

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

即使 $null 具有 Count 屬性,除非傳回 0

PS> $null.Count
0

稍後在本文中討論檢查 $null 或空白陣列時,我將重溫這裡的一些陷阱。

一次性錯誤

因為陣列從索引 0 開始,因此常會出現常見的程式設計錯誤。 可以透過兩種方式來導入非一次性錯誤。

第一個是精神上認為您想要第二個專案,並使用 2 的索引,並真正取得第三個專案。 或者,假設您有四個專案,而您想要最後一個專案,因此您可以使用計數來存取最後一個專案。

$data[ $data.Count ]

PowerShell 完全允許您這麼做,並確切地提供了索引 4:$null的項目。 您應該使用我們在上面介紹過的 $data.Count - 1-1

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

您可以在這裡使用 -1 索引來取得最後一個元素。

PS> $data[ -1 ]
Three

李戴利還向我指出,我們可以使用 $data.GetUpperBound(0) 來取得最大索引編號。

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

第二個最常見的方式是遍歷清單,卻沒有在正確的時間停止。 當我們談論使用 for 循環時,我會重新討論這個。

更新項目

我們可以使用相同的索引來更新陣列中的現有專案。 這可讓我們直接存取以更新個別專案。

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

如果我們嘗試更新超出最後一個元素的項目,會出現 Index was outside the bounds of the array. 錯誤。

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

稍後,當我討論如何擴大陣列時,我會重新審視這個問題。

反覆運算

在某些時候,您可能需要遍歷整個清單,並針對陣列中的每個項目執行一些動作。

管線

陣列與 PowerShell 管線很適合一起使用。 這是處理這些值的最簡單方式之一。 當您將陣列傳遞至管道時,陣列中的每個項目都會個別處理。

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

如果您以前沒見過 $PSItem,就知道這與 $_相同。 您可以使用其中一個,因為它們都代表管線中的目前物件。

ForEach 迴圈

foreach 迴圈搭配集合運作良好。 使用語法:foreach ( <variable> in <collection> )

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

ForEach 方法

我傾向於忘記這個,但它適用於簡單的作業。 PowerShell 允許您在集合中呼叫 ForEach()

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

ForEach() 需要一個作為腳本區塊的參數。 您可以卸除括弧,並只提供腳本區塊。

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

這是較不知名的語法,但運作方式完全相同。 PowerShell 4.0 已新增這個 ForEach 方法。

For 迴圈

大多數其他語言中大量使用 for 迴圈,然而在PowerShell中比較少看到。 當您看到時,通常是在遍歷陣列的情境下。

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

我們做的第一件事是將 $index 初始化為 0。 然後,我們新增條件,$index 必須小於 $data.Count。 最後,我們會指定每次迴圈時,都必須將索引增加 1。 在此情況下,$index++$index = $index + 1的縮寫。 格式運算符-f) 用來在輸出字串中插入 $data[$index] 的值。

每當您使用 "for 循環" 時,請特別注意條件。 我在這裡使用了 $index -lt $data.Count。 只要條件稍微弄錯,很容易導致邏輯出現差一錯誤。 使用 $index -le $data.Count$index -lt ($data.Count - 1) 會有一點小錯誤。 這會導致您的結果處理太多或太少的項目。 這是傳統的斷斷續續錯誤。

切換迴圈

這是很容易忽視的。 如果您將陣列提供給 switch 語句,它會檢查陣列中的每個項目。

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

我們可以使用 switch 語句執行許多酷的事情。 我有另一篇文章專門說明這一點。

更新值

當您的陣列是一組字串或整數(值類型)時,有時候您可能會想要在遍歷這些值時更新陣列中的這些值。 上述大部分的循環都會使用迴圈中的變數來保存值的複本。 如果您更新該變數,則陣列中的原始值不會更新。

該語句的例外狀況是 for 迴圈。 如果您想遍歷陣列並更新其中的值,for 迴圈就是您要尋找的。

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

此範例會依索引取得值、進行一些變更,然後使用相同的索引來將其指派回去。

對象的陣列

到目前為止,我們在陣列中放置的唯一的元素是實值型別,但陣列也可以包含物件。

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

當您將物件指派給變數時,許多 Cmdlet 會以數位的形式傳回物件的集合。

$processList = Get-Process

我們已經討論的所有基本功能仍然適用於物件的陣列,不過有一些需要注意的細節。

存取屬性

我們可以使用索引來存取集合中的個別專案,就像實值型別一樣。

PS> $data[0]

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

我們可以直接存取和更新屬性。

PS> $data[0].FirstName

Kevin

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

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

陣列屬性

一般而言,您必須列舉像這樣的完整清單,才能存取所有屬性:

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

Marquette
Doe

或使用 Select-Object -ExpandProperty 指令。

PS> $data | Select-Object -ExpandProperty LastName

Marquette
Doe

但 PowerShell 可讓我們直接要求 LastName。 PowerShell 會為我們列舉所有專案,並傳回乾淨的清單。

PS> $data.LastName

Marquette
Doe

列舉仍會發生,但我們看不到其背後的複雜度。

Where-Object 篩選

這就是 Where-Object 派上用場的地方,因此我們可以根據物件的屬性來篩選和選取我們想要從陣列中取得的內容。

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

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

我們可以撰寫相同的查詢語句,以取得我們正在尋找的 FirstName

$data | where FirstName -EQ Kevin

Where()

陣列有一個 Where() 方法,您可以使用該方法指定篩選的 scriptblock

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

此功能已在PowerShell 4.0中新增。

更新迴圈中的物件

使用實值型別時,更新陣列的唯一方法是使用 for 循環,因為我們必須知道索引才能取代值。 我們有更多的物件選項,因為它們是參考型別。 以下是快速範例:

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

這個迴圈會遍歷 $data 陣列中的每個物件。 因為物件是參考型別,$person 變數會參考陣列中完全相同的物件。 因此,更新其屬性會更新原始物件。

您仍然無法以這種方式取代整個物件。 如果您嘗試將新的物件指派給 $person 變數,您將更新變數的參考,使其不再指向陣列中的原始物件,而是指向新的物件。 這並不像您預期般運作:

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

運營商

PowerShell 中的運算子也適用於陣列。 其中一些工作方式稍有不同。

-參加

-join 運算子是最明顯的運算子,因此讓我們先看看。 我喜歡 -join 運算符,並經常使用它。 它會使用您指定的字元或字串聯結陣列中的所有專案。

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

我喜歡 -join 運算符的一個特點是它可以處理單一項目。

PS> 1 -join '-'
1

我在日志記錄和冗長訊息中使用此功能。

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

-join $array

這是李戴利向我指出的一個聰明的技巧。 如果您想要將所有項目連接在一起而不使用分隔符,您可以這樣做:

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

您可以將 -join 與陣列作為參數使用,且不需前綴詞。 看看這個範例,了解我所談論的內容。

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

-replace 和 -split

其他運算元,例如 -replace-split 會在陣列中的每個項目上執行。 我不能說我曾經這樣使用過它們, 但這裡有一個例子。

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

-包含

-contains 運算子可讓您檢查值的陣列,以查看其是否包含指定的值。

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

-in

當您有想要驗證的單一值符合數個值之一時,您可以使用 -in 運算符。 值會位於運算子的左邊,而陣列則位於右邊。

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

如果清單很大,這可能會變得很昂貴。 如果我檢查多個值,我通常會使用 regex 模式。

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

PS> 'green' -match $pattern
True

-eq 和 -ne

相等和陣列可能會變得複雜。 當陣列位於左側時,會比較每個項目。 它會傳回符合的物件,而不是傳回 True

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

當您使用 -ne 運算符時,我們會取得所有不等於我們的值的數值。

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

當您在 if() 語句中使用這個值時,傳回的值就是 True 值。 如果未傳回任何值,則它是 False 值。 這兩個下一個語句都會評估為 True

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

等一下在我們談論測試 $null時,我會再回來看看這一點。

-匹配

-match 運算子會嘗試比對集合中的每個項目。

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

當您搭配單一值使用 -match 時,特殊變數 $Matches 會填入相符資訊。 以這種方式處理陣列時,情況並非如此。

我們可以使用 Select-String相同的方法。

$servers | Select-String SQL

我仔細查看了在另一篇名為 《多種使用 regex方法》的文章中的 Select-String-match$Matches 變數。

$null或空白

測試 $null 或空陣列可能很棘手。 以下是陣列的常見陷阱。

乍看之下,這句話看起來應該可行。

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

但我剛才覆述了 -eq 如何檢查陣列中的每個項目。 因此,我們可以有一個包含數個項目且具有單一 $null 值的陣列,並且會被評估為 $true

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

這就是為什麼將 $null 放在運算符左側是最佳作法。 這會使此情況不再是一個問題。

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

$null 陣列與空陣列不同。 如果您知道您有陣列,請檢查其中的物件計數。 如果陣列是 $null,則計數是 0

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

這裡有一個陷阱需要注意。 即使您只有單一物件,也可以使用 Count,除非該物件是 PSCustomObject。 這是 PowerShell 6.1 中修正的錯誤。 這是好消息,但很多人仍然在5.1,需要注意它。

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

如果您仍在使用 PowerShell 5.1,可以先將物件包裝在陣列中,再檢查其計數,以獲得準確的計算結果。

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

為了確保萬無一失,請檢查 $null,然後確認數量。

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

所有 -eq

我最近在 Reddit 上看到有人詢問如何確認陣列中的每個值都符合指定的值。 Reddit 使用者 u/bis 提出了一個聰明的解決方案,該方案會檢查是否有任何不正確的值,然後調整結果。

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

將元素加入陣列中

此時,您開始想知道如何將項目新增至陣列。 快速答案是,您無法。 陣列是在記憶體中的固定大小。 如果您需要將陣列擴展或新增單一元素至陣列中,則需要建立新的陣列,然後從舊陣列中複製所有值。 不過,這聽起來像是許多工作,但 PowerShell 會隱藏建立新陣列的複雜性。 PowerShell 會實作陣列的加法運算子 (+)。

備註

PowerShell 不會實作減法運算。 如果您想要有彈性的陣列替代方案,則必須使用 泛型 List 物件。

陣列加法

我們可以使用加法運算子與陣列來建立新的陣列。 因此,假設有下列兩個陣列:

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

我們可以將它們加在一起得到新的陣列。

PS> $first + $second

Zero
One
Two
Three

Plus 等於 +=

我們可以在原地建立新的陣列,並將項目添加到其中,如下所示:

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

請記住,每次您使用 +=,都會複製並建立新的陣列。 對於小型數據集來說,這不是一個問題,但它的規模非常差。

管線指派

您可以將任何管線的結果指派給變數。 如果它包含多個項目,那麼它就是一個陣列。

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

通常當我們想到使用管道時,我們會聯想到典型的 PowerShell 單行指令。 我們可以將 foreach() 語句和其他迴圈搭配於管線中使用。 因此,我們可以將項目放入管線,而不是在迴圈中將項目新增至陣列。

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

陣列類型

根據預設,PowerShell 中的陣列會建立為 [psobject[]] 類型。 這可讓它包含任何類型的物件或值。 這樣運作,因為一切是繼承自 PSObject 類型。

强類型陣列

您可以使用類似的語法來建立任何類型的陣列。 當您建立強型別陣列時,它只能包含指定類型的值或物件。

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(陣列列表)

將元素新增至陣列是其最大限制之一,但我們可以轉向一些其他集合來解決這個問題。

ArrayList 通常是在我們需要更快速處理的陣列時,首先考慮的選擇之一。 它在我們需要的每個地方都像物件陣列,但能快速處理新增項目。

以下是我們如何建立 ArrayList 並將項目新增至其中的方式。

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

我們呼叫 .NET 以取得此類型。 在此情況下,我們會使用預設建構函式來建立它。 然後我們會呼叫 Add 方法來將項目加入其中。

我在行開頭使用 [void] 的原因是隱藏傳回碼。 某些 .NET 呼叫會執行此動作,並可以建立非預期的輸出。

如果陣列中只有字串,不妨考慮使用 StringBuilder。 這幾乎是一樣的東西,但有一些僅用於處理字串的方法。 StringBuilder 專為效能而設計。

人們通常會從陣列移至 ArrayList。 但那是一個 C# 沒有泛型支持的時代。 ArrayList 已被棄用,以支持泛型 List[]

泛型清單

泛型類型是 C# 中的特殊類型,定義一般化類別,而使用者指定建立時所使用的數據類型。 因此,如果您想要數位或字串清單,您可以定義想要 intstring 類型的清單。

以下是建立字串清單的方式。

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

或數字的清單。

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

我們可以將現有的陣列轉換成這樣的清單,而不先建立 物件:

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

我們可以在PowerShell 5和更新版本中使用 using namespace 語句來縮短語法。 using 語句必須是腳本的第一行。 藉由宣告命名空間,PowerShell 可讓您在參考數據類型時省略數據類型。

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

這使得 List 更容易使用。

您有類似的 Add 方法可供您使用。 不同於 ArrayList,Add 方法上沒有傳回值,因此我們不需要 void 它。

$myList.Add(10)

我們仍然可以像其他陣列一樣存取元素。

PS> $myList[-1]
10

List[psobject]

您可以擁有任何類型的清單,但當您不知道物件的類型時,您可以使用 [List[psobject]] 來包含它們。

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

Remove()

ArrayList 和泛型 List[] 都支援從集合中移除專案。

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

使用實值型別時,它會從清單中移除第一個類型。 您可以反覆呼叫它,以繼續移除該值。 如果您有參考類型,則必須提供您想要移除的物件。

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

如果 remove 方法能夠從集合中尋找和移除專案,則會傳回 true

更多集合

有許多其他的集合可以使用,但這些是很好的泛型陣列替代選項。 如果您有興趣深入瞭解這些選項,請看看這個 Gist馬克·克勞斯 放在一起。

其他細微差別

既然我已經涵蓋了所有主要功能,以下是我總結之前想要提及的一些事項。

已設定大小的陣列

我提到,一旦建立陣列,就無法變更陣列的大小。 我們可以使用 new($size) 建構函式呼叫它,以建立預先決定大小的陣列。

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

相乘陣列

有趣的小訣竅是,您可以將陣列乘以整數。

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

使用 0 初始化

常見的案例是您想要建立具有所有零的陣列。 如果您只會有整數,則強型別整數陣列的預設值為所有零。

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

我們也可以使用乘法技巧來進行這項工作。

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

乘法技巧的好處是您可以使用任何值。 因此,如果您寧願將 255 做為預設值,這是一個很好的方法。

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

巢狀陣列

陣列內的陣列稱為巢狀陣列。 我不會在PowerShell中使用這些太多,但我在其他語言中會使用它們更多。 當您的資料呈現網格狀結構時,請考慮使用多重陣列。

以下是我們可以建立二維陣列的兩種方式。

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

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

在這些範例中,逗號非常重要。 我先前提供了一個跨多行的一般陣列範例,其中逗號是選擇性的。 這不是多維度陣列的情況。

我們現在使用索引表示法的方式會稍微變更,因為我們有巢狀陣列。 使用上述的 $data,這就是我們如何存取值 3。

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

為每個陣列巢狀層級新增一組括號。 最外層的括弧適用於最外層的陣列,然後逐步向內處理。

Write-Output -NoEnumerate

PowerShell 喜歡解除包裝或列舉陣列。 這是 PowerShell 使用管線方式的核心層面,但有時候您不希望使其發生。

我通常會使用管線將對象傳送至 Get-Member,以深入了解它們。 當我使用管線將陣列傳送至它時,它會解除包裝,Get-Member 只會識別陣列的成員,而不是陣列本身。

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

若要防止陣列的拆封,您可以使用 Write-Output -NoEnumerate

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

我有第二種方式,更像是駭客(我試圖避免這樣的駭客攻擊)。 您可以在使用管線傳送陣列之前,將逗號放在陣列前面。 這會將 $data 包裝進一個新陣列,其中它是唯一的元素,因此在解除外部陣列包裝後,我們會得到解包的 $data

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

傳回陣列

當您從函式輸出或傳回值時,也會發生陣列解除包裝的情況。 如果您將輸出指派給變數,因此這不是常見的問題,您仍然可以取得陣列。

zh-TW: 問題在於您有了一個新的陣列。 如果這是問題,您可以使用 Write-Output -NoEnumerate $arrayreturn ,$array 來解決此問題。

別的東西?

我知道這一切都是很多資訊要消化的。 我希望你每次閱讀這篇文章時都能學到一些東西,並且它能長期成為你的良好參考。 如果您發現這些資訊對您有幫助,請分享給其他您認為可能受益的人。

我建議您從這裡開始,查看或閱讀我撰寫的與 哈希表相關的類似文章。