【问题标题】:Powershell Multidimensional ArraysPowershell 多维数组
【发布时间】:2012-03-12 22:03:27
【问题描述】:

我有一种用其他语言做数组的方法,如下所示:

$x = "David"
$arr = @()

$arr[$x]["TSHIRTS"]["SIZE"] = "M"

这会产生错误。

【问题讨论】:

  • 如前所述,您发布的代码是字典或哈希,而不是普通数组。

标签: powershell


【解决方案1】:

您正在尝试创建关联数组(哈希)。试试以下 命令序列

$arr=@{}
$arr["david"] = @{}
$arr["david"]["TSHIRTS"] = @{}    
$arr["david"]["TSHIRTS"]["SIZE"] ="M"
$arr.david.tshirts.size

注意哈希和数组的区别

$a = @{} # hash
$a = @() # array

数组只能有非负整数作为索引

【讨论】:

  • 像个魅力伙伴一样工作!谢谢!
  • 这是 3D 哈希表的示例吗?
  • 请注意,负索引在 Powershell 中是有意义的。 $arr[-1] 是数组中的最后一项,$arr[-2] 是倒数第二项,依此类推。
【解决方案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

【讨论】:

  • 你不一定非得访问.NET:[PS] C:\>$array = @(,@(,@(,@()))) [PS] C:\ >$array[0][0][0] = 1
  • 无论如何,它们并不完全相同。一个必须引用为 $array[n,n],另一个引用为 $array[n][n]。
  • 使用 .NET 还可以更轻松地预先生成尺寸大小。使用上面提到的 PS 方法,您必须自己预先生成它或使用添加运算符来添加新成员。你不能简单地写$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。
  • @DaveF 和 $array2.GetUpperBound(n) 根据索引号查找长度,这是您在遍历数组时需要的。相当于$array.GetLength(n) - 1。顺便说一下,此方法也可用于普通 PS 数组,您只需为 n 输入 0,因为它是一维的。
【解决方案3】:

扩展上面 manojlds 所说的是,您可以嵌套 Hashtables。它可能不是真正的多维数组,但可以为您提供一些关于如何构造数据的想法。一个例子:

$hash = @{}

$computers | %{
    $hash.Add(($_.Name),(@{
        "Status" = ($_.Status)
        "Date"   = ($_.Date)
    }))
}

这很酷的是您可以参考以下内容:

($hash."Name1").Status

此外,它比数组查找内容要快得多。我用它来比较数据,而不是在数组中使用匹配。

$hash.ContainsKey("Name1")

希望对你有所帮助!

-亚当

【讨论】:

    【解决方案4】:

    知道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 algorithmhash table 慢。
    请注意,使用自定义对象数组的优势是可以轻松搜索其他任何内容,例如每个穿着 MT 恤 的人:

    $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.
    

    【讨论】:

    • 这应该是公认的答案......简单的 assoc 对象数组 - 漂亮的解决方案! :-)
    • [PSObject] 也可以。少打字,多喝咖啡。
    【解决方案5】:

    这是一个简单的多维字符串数组。

    $psarray = @(
     ('Line' ,'One' ),
     ('Line' ,'Two')
    )
    
    foreach($item in $psarray)
    {
        $item[0]
        $item[1]
    }
    

    输出:

    Line
    One
    Line
    Two
    

    【讨论】:

      【解决方案6】:

      你也可以使用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],否则脚本会发疯。

      【讨论】:

        【解决方案7】:

        此处的另一个线程指出了如何在 Powershell 中添加到多维数组。我不知道是否有理由不使用此方法,但它适用于我的目的。

        $array = @()
        $array += ,@( "1", "test1","a" )
        $array += ,@( "2", "test2", "b" )
        $array += ,@( "3", "test3", "c" )
        

        【讨论】:

          【解决方案8】:

          我发现在数组中制作数组的解决方案非常酷。

          $GroupArray = @()
          foreach ( $Array in $ArrayList ){
              $GroupArray += @($Array , $null)
          }
          $GroupArray = $GroupArray | Where-Object {$_ -ne $null}
          

          【讨论】:

            【解决方案9】:

            使用 .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
            

            【讨论】:

              【解决方案10】:

              从上面借来的:

              $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
              

              【讨论】:

                【解决方案11】:

                二维数组也可以这样定义为锯齿数组:

                $array =  New-Object system.Array[][] 5,5
                

                这有一个很好的功能,

                $array[0]
                

                输出一个一维数组,包含$array[0][0]$array[0][4]。 根据您的情况,您可能更喜欢它而不是$array = New-Object 'object[,]' 5,5。 (我会在上面对 CB 发表评论,但 stackoverflow 还没有让我这样做)

                【讨论】:

                  猜你喜欢
                  • 2015-06-13
                  • 2021-11-02
                  • 1970-01-01
                  • 2013-08-19
                  • 1970-01-01
                  • 2011-02-22
                  • 1970-01-01
                  • 2018-01-26
                  • 1970-01-01
                  相关资源
                  最近更新 更多