【发布时间】:2012-03-12 22:03:27
【问题描述】:
我有一种用其他语言做数组的方法,如下所示:
$x = "David"
$arr = @()
$arr[$x]["TSHIRTS"]["SIZE"] = "M"
这会产生错误。
【问题讨论】:
-
如前所述,您发布的代码是字典或哈希,而不是普通数组。
标签: powershell
我有一种用其他语言做数组的方法,如下所示:
$x = "David"
$arr = @()
$arr[$x]["TSHIRTS"]["SIZE"] = "M"
这会产生错误。
【问题讨论】:
标签: powershell
您正在尝试创建关联数组(哈希)。试试以下 命令序列
$arr=@{}
$arr["david"] = @{}
$arr["david"]["TSHIRTS"] = @{}
$arr["david"]["TSHIRTS"]["SIZE"] ="M"
$arr.david.tshirts.size
注意哈希和数组的区别
$a = @{} # hash
$a = @() # array
数组只能有非负整数作为索引
【讨论】:
$arr[-1] 是数组中的最后一项,$arr[-2] 是倒数第二项,依此类推。
来自 powershell.com:
PowerShell 支持两种类型的多维数组:交错数组和真正的多维数组。
锯齿状数组是将数组存储为元素的普通 PowerShell 数组。这是一种非常划算的存储方式,因为维度可以有不同的大小:
$array1 = 1,2,(1,2,3),3
$array1[0]
$array1[1]
$array1[2]
$array1[2][0]
$array1[2][1]
真正的多维数组总是类似于方阵。要创建这样的数组,您需要访问 .NET。下一行创建一个包含 10 和 20 个元素的二维数组,类似于 10x20 矩阵:
$array2 = New-Object 'object[,]' 10,20
$array2[4,8] = 'Hello'
$array2[9,16] = 'Test'
$array2
对于 3 维数组 10*20*10
$array3 = New-Object 'object[,,]' 10,20,10
【讨论】:
$array[0]0][1] = 2,因为它超出了数组的范围。而$array[1][0][0] = 2 将索引一个空数组。如果您想要一个不理想的随机访问矩阵。
GetLength 方法来获取特定维度的元素数。例如,$array2.GetLength(0) 将为 $array2 = New-Object 'object[,]' 10,20 返回 10,$array2.GetLength(1) 将返回 20。
$array2.GetUpperBound(n) 根据索引号查找长度,这是您在遍历数组时需要的。相当于$array.GetLength(n) - 1。顺便说一下,此方法也可用于普通 PS 数组,您只需为 n 输入 0,因为它是一维的。
扩展上面 manojlds 所说的是,您可以嵌套 Hashtables。它可能不是真正的多维数组,但可以为您提供一些关于如何构造数据的想法。一个例子:
$hash = @{}
$computers | %{
$hash.Add(($_.Name),(@{
"Status" = ($_.Status)
"Date" = ($_.Date)
}))
}
这很酷的是您可以参考以下内容:
($hash."Name1").Status
此外,它比数组查找内容要快得多。我用它来比较数据,而不是在数组中使用匹配。
$hash.ContainsKey("Name1")
希望对你有所帮助!
-亚当
【讨论】:
知道PowerShell pipes objects between cmdlets,在PowerShell中使用PSCustomObjects数组更常见:
$arr = @(
[PSCustomObject]@{Name = 'David"; Article = 'TShirt"; Size = 'M"}
[PSCustomObject]@{Name = 'Eduard"; Article = 'Trouwsers"; Size = 'S"}
)
或者对于旧 PowerShell 版本 (PSv2):
$arr = @(
New-Object PSObject -Property @{Name = 'David"; Article = 'TShirt"; Size = 'M"}
New-Object PSObject -Property @{Name = 'Eduard"; Article = 'Trouwsers"; Size = 'S"}
)
然后 grep 您的选择,例如:
$arr | Where {$_.Name -eq 'David' -and $_.Article -eq 'TShirt"} | Select Size
或者在较新的 PowerShell(核心)版本中:
$arr | Where Name -eq 'David' | Where Article -eq 'TShirt' | Select Size
或者(只需获取大小):
$arr.Where{$_.Name -eq 'David' -and $_.Article -eq 'TShirt'}.Size
附录 2020-07-13
正如 cmets 中所提到的,使用自定义对象数组更直接并且可以节省输入,如果您想进一步了解这一点,您甚至可以使用ConvertForm-Csv(或Import-Csv)cmdlet 来构建数组:
$arr = ConvertFrom-Csv @'
Name,Article,Size
David,TShirt,M
Eduard,Trouwsers,S
'@
或更具可读性:
$arr = ConvertFrom-Csv @'
Name, Article, Size
David, TShirt, M
Eduard, Trouwsers, S
'@
注意:包含空格或特殊字符的值需要双引号
或者使用外部 cmdlet,例如 ConvertFrom-SourceTable,它读取固定宽度的表格格式:
$arr = ConvertFrom-SourceTable '
Name Article Size
David TShirt M
Eduard Trouwsers S
'
使用自定义对象数组的缺点是它比使用 binary search algorithm 的 hash table 慢。
请注意,使用自定义对象数组的优势是可以轻松搜索其他任何内容,例如每个穿着 M 号 T 恤 的人:
$arr | Where Article -eq 'TShirt' | Where Size -eq 'M' | Select Name
从对象数组构建二进制搜索索引:
$h = @{}
$arr | ForEach-Object {
If (!$h.ContainsKey($_.Name)) { $h[$_.Name] = @{} }
If (!$h[$_.Name].ContainsKey($_.Article)) { $h[$_.Name][$_.Article] = @{} }
$h[$_.Name][$_.Article] = $_ # Or: $h[$_.Name][$_.Article]['Size'] = $_.Size
}
$h.david.tshirt.size
M
注意:引用Set-StrictMode中不存在的哈希表键会导致错误:
Set-StrictMode -Version 2
$h.John.tshirt.size
PropertyNotFoundException: The property 'John' cannot be found on this object. Verify that the property exists.
【讨论】:
[PSObject] 也可以。少打字,多喝咖啡。
这是一个简单的多维字符串数组。
$psarray = @(
('Line' ,'One' ),
('Line' ,'Two')
)
foreach($item in $psarray)
{
$item[0]
$item[1]
}
输出:
Line
One
Line
Two
【讨论】:
你也可以使用System.Collections.ArrayList 来创建一个数组或任何你想要的数组。
这是一个例子:
$resultsArray= New-Object System.Collections.ArrayList
[void] $resultsArray.Add(@(@('$hello'),2,0,0,0,0,0,0,1,1))
[void] $resultsArray.Add(@(@('$test', '$testagain'),3,0,0,1,0,0,0,1,2))
[void] $resultsArray.Add("ERROR")
[void] $resultsArray.Add(@(@('$var', '$result'),5,1,1,0,1,1,0,2,3))
[void] $resultsArray.Add(@(@('$num', '$number'),3,0,0,0,0,0,1,1,2))
一个问题,如果你认为它是一个问题,你不能设置一个限制。另外,你需要使用[void],否则脚本会发疯。
【讨论】:
此处的另一个线程指出了如何在 Powershell 中添加到多维数组。我不知道是否有理由不使用此方法,但它适用于我的目的。
$array = @()
$array += ,@( "1", "test1","a" )
$array += ,@( "2", "test2", "b" )
$array += ,@( "3", "test3", "c" )
【讨论】:
我发现在数组中制作数组的解决方案非常酷。
$GroupArray = @()
foreach ( $Array in $ArrayList ){
$GroupArray += @($Array , $null)
}
$GroupArray = $GroupArray | Where-Object {$_ -ne $null}
【讨论】:
使用 .net 语法(如上面提到的 CB)
您还可以为您的“表格”数组添加连贯性...
如果你定义了一个数组...
并且您尝试存储不同的类型
Powershell 会“提醒”您:
$a = New-Object 'byte[,]' 4,4
$a[0,0] = 111; // OK
$a[0,1] = 1111; // Error
Powershell 当然会“帮助”你
在明显的转换中:
$a = New-Object 'string[,]' 2,2
$a[0,0] = "1111"; // OK
$a[0,1] = 111; // OK also
【讨论】:
从上面借来的:
$arr = ConvertFrom-Csv @'
Name,Article,Size
David,TShirt,M
Eduard,Trouwsers,S
'@
打印$arr:
$arr
Name Article Size
---- ------- ----
David TShirt M
Eduard Trouwsers S
现在选择“大卫”
$arr.Where({$_.Name -eq "david"})
Name Article Size
---- ------- ----
David TShirt M
现在如果你想知道“大卫”的大小
$arr.Where({$_.Name -eq "david"}).size
M
【讨论】:
二维数组也可以这样定义为锯齿数组:
$array = New-Object system.Array[][] 5,5
这有一个很好的功能,
$array[0]
输出一个一维数组,包含$array[0][0] 到$array[0][4]。
根据您的情况,您可能更喜欢它而不是$array = New-Object 'object[,]' 5,5。
(我会在上面对 CB 发表评论,但 stackoverflow 还没有让我这样做)
【讨论】: