Tuples/ArrayList 对

Tuples/ArrayList of pairs

我实际上是在尝试创建一个配对列表,事实证明这非常困难

在有人提到 Hashtables 之前请注意,会有我不关心的重复项。

例如,如果我这样做

$b = @{"dog" = "cat"}

我明白了

名称值
---- -----
狗猫

哪个好。但是,我无法添加

之类的内容
$b += @{"dog" = "horse"}

Item has already been added. Key in dictionary: 'dog' Key being added: 'dog'

我只是想创建一个 table 数据 ,我可以使用 .Add()+= 之类的东西将其添加到

我相信哈希表列表应该可以完成您所追求的。

$ht = @{foo='bar'}
$list = [System.Collections.Generic.List[hashtable]]::new()
$list.Add($ht)
$list.Add($ht)
$list.Add($ht)
$list

提供了一种有效且高效的解决方案 - 尽管有点晦涩难懂。

创建哈希表的 数组 是最简单的解决方案,但重要的是要注意 "extending" 数组意味着隐式地 重新创建 它,鉴于数组是固定大小的数据结构,这可能会成为多次迭代的性能问题:

# Using array-construction operator ",", create a single-element array
# containing a hashtable
$b = , @{ dog = "cat"} 

# "Extend" array $b by appending another hashtable.
# Technically, a new array must be allocated that contains the original array's
# elements plus the newly added one.
$b += @{ dog = "horse"}

This GitHub issue 讨论了未来可能的增强功能,使 PowerShell 本机支持可有效扩展的类似列表的数据类型,或者甚至 default 这种数据类型。 (从 Windows PowerShell v5.1 / PowerShell Core 6.2.0 开始,PowerShell 默认为 [object[]] 类型的固定大小数组)。

如果你想要一个元组列表,我建议实际构建一个 tuples:

的列表
$list = @()

$tuple1 = New-Object 'Tuple[String,String]' 'dog', 'cat'
$tuple2 = New-Object 'Tuple[String,String]' 'dog', 'horse'

$list += $tuple1
$list

# Output:
#
# Item1 Item2 Length
# ----- ----- ------
# dog   cat        2

$list += $tuple2
$list

# Output:
#
# Item1 Item2 Length
# ----- ----- ------
# dog   cat        2
# dog   horse      2

请注意,在这个例子中 $list 是一个常规数组,这意味着,正如 在他的回答中指出的那样,用 += 赋值运算符附加到它会重新创建大小增加 1 的数组,将新项放入新的空槽中,然后替换原来的数组。对于少量追加操作,这通常不是大问题,但随着追加操作数量的增加,性能影响变得显着。

使用 ArrayList 而不是普通数组可以避免此问题:

$list = New-Object Collections.ArrayList

$tuple1 = New-Object 'Tuple[String,String]' 'dog', 'cat'
$tuple2 = New-Object 'Tuple[String,String]' 'dog', 'horse'

$list.Add($tuple1) | Out-Null
$list

# Output:
#
# Item1 Item2 Length
# ----- ----- ------
# dog   cat        2

$list.Add($tuple2) | Out-Null
$list

# Output:
#
# Item1 Item2 Length
# ----- ----- ------
# dog   cat        2
# dog   horse      2

ArrayList 对象的 Add() 方法输出附加项目的索引。 Out-Null 抑制在大多数情况下不需要的输出。如果您想使用这些索引号,您可以将它们收集到一个变量中而不是丢弃它们 ($i = $list.Add($t1))。

如果你想避免一直指定新元组的类型,你可以将它包装成一个可重用的函数,如下所示:

function New-Tuple {
    Param(
        [Parameter(Mandatory=$true)]
        [ValidateCount(2,2)]
        [string[]]$Values
    )

    New-Object 'Tuple[String,String]' $Values
}

$tuple1 = New-Tuple 'dog', 'cat'
$tuple2 = New-Tuple 'dog', 'horse'

或者,以更通用的方式,像这样:

function New-Tuple {
    Param(
        [Parameter(
            Mandatory=$true,
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true
        )]
        [ValidateCount(2,20)]
        [array]$Values
    )

    Process {
        $types = ($Values | ForEach-Object { $_.GetType().Name }) -join ','
        New-Object "Tuple[$types]" $Values
    }
}

$tuples = ('dog', 'cat'), ('dog', 'horse') | New-Tuple

感谢 mklement0,下面可能是最简单的解决方案

$b = , @{ dog = "cat"} 
$b += @{ dog = "horse"}

并且 Persistent13 的方法也产生了一条简单的路线

$ht = @{foo='bar'}
$list = [System.Collections.Generic.List[hashtable]]::new()
$list.Add($ht)
$list.Add($ht)
$list.Add($ht)
$list

我想我只是感到惊讶,没有一种更根深蒂固的方法来获得我认为漂亮的 basic/standard 对象类型