当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 关于数组你想知道的一切

作者:精品下载站 日期:2024-12-14 03:04:33 浏览:14 分类:玩电脑

关于数组你想知道的一切


数组是大多数编程语言的基本语言功能。它们是难以避免的值或对象的集合。让我们仔细看看数组以及它们所提供的一切。

笔记

本文的原始版本出现在@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 在控制台快速创建字符串。

$data = Write-Output Zero One Two Three

这很方便,因为当参数接受字符串时,您不必在字符串两边加上引号。我永远不会在脚本中这样做,但在控制台中这是公平的游戏。

访问项目

现在您已经有了一个包含项目的数组,您可能想要访问和更新这些项目。

抵消

要访问单个项目,我们使用方括号 [] 以及从 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] 通过给出数组中的第一个和最后一个项目(以及没有其他值)。这是一个更大的例子:

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一个空数组

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

因此,在尝试访问数组中的元素之前,请确保数组不是 $null

数数

数组和其他集合有一个 count 属性,可以告诉您数组中有多少项。

PS> $data.count
4

PowerShell 3.0 为大多数对象添加了计数属性。您可以有一个对象,它应该为您提供 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

Lee Dailey 还向我指出,我们可以使用 $data.GetUpperBound(0) 来获取最大索引号。

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

第二种最常见的方法是迭代列表时而不是在正确的时间停止。当我们讨论使用 for 循环时,我将重新讨论这一点。

更新项目

我们可以使用相同的索引来更新数组中的现有项目。这使我们能够直接访问更新单个项目。

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

如果我们尝试更新最后一个元素之后的项目,则会收到 Index was Outside 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 ( in )

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

这是一种鲜为人知的语法,但其工作原理是一样的。此 foreach 方法是在 PowerShell 4.0 中添加的。

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 语句做很多很酷的事情。我还有另一篇文章专门讨论这个问题。

  • 关于 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 cmdlet。

PS> $data | Select-Object -ExpandProperty LastName

Marquette
Doe

但是 PowerShell 为我们提供了直接请求 LastName 的能力。 PowerShell 为我们枚举了所有这些并返回一个干净的列表。

PS> $data.LastName

Marquette
Doe

枚举仍然发生,但我们看不到其背后的复杂性。

地点对象过滤

这就是 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 运算符是最明显的,所以让我们先看一下它。我喜欢 -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.

-加入$数组

这是李·戴利向我指出的一个巧妙的技巧。如果您想在没有分隔符的情况下连接所有内容,请不要这样做:

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

您可以使用 -join 将数组作为不带前缀的参数。看一下这个例子就知道我在说什么了。

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

- 替换和 - 分割

其他运算符(例如 -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

-contains 运算符允许您检查值数组以查看它是否包含指定值。

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

-in

当您想要验证单个值是否与多个值之一匹配时,可以使用 -in 运算符。值位于运算符的左侧,数组位于运算符的右侧。

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

如果列表很大,这可能会变得昂贵。如果我要检查多个值,我经常使用正则表达式模式。

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

-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

我在另一篇名为“使用正则表达式的多种方法”的文章中仔细研究了 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

加等于+=

我们可以就地创建一个新数组并向其中添加一个项目,如下所示:

$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

更多收藏

还有许多其他集合可以使用,但这些是很好的通用数组替代品。如果您有兴趣了解更多这些选项,请查看 Mark Kraus 整理的要点。

其他细微差别

现在我已经介绍了所有主要功能,在总结之前,我还想提一下以下几件事。

预先确定大小的数组

我提到过数组一旦创建就无法更改其大小。我们可以通过使用 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

为数组嵌套的每一层添加一组括号。第一组括号用于最外面的数组,然后您可以从那里开始操作。

写输出-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[]
...

返回一个数组

当您从函数输出或返回值时,也会发生这种数组展开。如果将输出分配给变量,您仍然可以获得数组,因此这通常不是问题。

问题是你有一个新数组。如果这是一个问题,您可以使用 Write-Output -NoEnumerate $arrayreturn ,$array 来解决它。

还要别的吗?

我知道这需要考虑的内容有很多。我希望您每次阅读本文时都能从中学到一些东西,并且在未来很长一段时间内它都会成为您很好的参考。如果您发现这有帮助,请与您认为可以从中获得价值的其他人分享。

从这里,我建议您查看我写的有关哈希表的类似文章。

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯