哈希表 - 组合未知数量的哈希表

Hashtable - Combining unknown number of hashtables

我正在尝试以编程方式将未知数量的散列table组合成更大的散列table。每个人 table 将拥有相同的密钥。我尝试只附加它,但它会引发有关重复键的错误。

ForEach ($Thing in $Things){
  $ht1 = New-Object psobject @{
    Path = $Thing.path
    Name = $Thing.name
  }
  $ht2 += $ht1
}

这会引发错误

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

最后的结果就是以后我可以说

ForEach ($Item in $ht2){
  write-host $Item.path
  write-host $Item.name
}

向散列添加一个元素 table 实际上 fails 如果已经有一个具有相同键的元素。要克服这个问题,首先要查看该元素是否存在。像这样,

if(-not $ht2.ContainsKey($thing.name)){
    $ht2.Add($thing.name, $thing.value)
}

也可以使用项目 属性 [] 进行检查,因为它 returns $null 用于不存在的元素。像这样,

if($ht2[$thing.name] -eq $null){
    $ht2.Add($thing.name, $thing.value)
}

如果这真的是关于合并 Hashtables 正如标题所说,那么基本上你有两个选项可以将第二个哈希表中的条目添加到第一个中。

1.使用静态方法Add()(第一项'wins')

这在vonPryz's answer中已经解释过了,但简而言之:

在哈希表中添加一个条目,其中的键已经存在于哈希表中,Add() 方法将抛出异常,因为哈希表中的所有键必须是唯一的。
为了克服这个问题,您需要检查是否存在具有该键的条目,如果存在,则不要添加来自第二个哈希的条目。

    foreach ($key in $secondHash.Keys) {
        if (!$firstHash.Contains($key)) {
            # only add the entry if the key (name) did not already exist
            $firstHash.Add($key, $secondHash[$key])  
        }
    }

这样,第一个哈希表中的所有条目都不会被覆盖,第二个哈希表中的重复条目将被丢弃。

2。 Overwriting/adding 不管是否存在(最后一项 'wins')

您也可以选择 'merge' 条目而无需像这样检查:

    foreach ($key in $secondHash.Keys) {
        # always add the entry even if the key (name) already exist
        $firstHash[$key] = $secondHash[$key]
    }

这样,如果一个条目已经存在于第一个散列中,其值将被覆盖第二个散列中的值。 如果该条目尚不存在,则将其简单地添加到第一个哈希表中。

但是,如果您想合并 而不 跳过或覆盖现有值怎么办?

在这种情况下,您需要想出一些方法来为要添加的条目创建唯一键。
像这样:

    foreach ($key in $secondHash.Keys) {
        if ($firstHash.Contains($key)) {
            # ouch, the key already exists.. 
            # now, we only want to add this if the value differs (no point otherwise)
            if ($firstHash[$key] -ne $secondHash[$key]) {
                # add the entry, but create a new unique key to store it under first
                # this example just adds a number between brackets to the key
                $num = 1
                do {
                    $newKey = '{0}({1})' -f $key, $num++
                } until (!$firstHash.Contains($newKey))
                # we now have a unique new key, so add it
                $firstHash[$newKey] = $secondHash[$key]
            }
        }
        else {
            # no worries, the key is unique
            $firstHash[$key] = $secondHash[$key]
        }
    }

事实证明,我的结果需要的是哈希表数组,而不是@WalterMitty 指出的哈希表的哈希表。我的最终代码是:

#varibale name ht2 保留以明确它与原始问题的关系

$ht2 = @()

ForEach ($Thing in $Things){
  $ht1 = New-Object psobject @{
    Path = $Thing.path
    Name = $Thing.name
  }
  $ht2 += $ht1
}

正在将我的评论转换为答案。

您可能想要创建的是哈希表数组。数组中的每一项对于每个键都可以有自己的值。此结构可以按照您在 post.

末尾的查询中指示的方式使用

试试这个:

$things = gci $home

$ht2 = @()       # create empty array

ForEach ($Thing in $Things){
  $ht1 = New-Object psobject @{
    Path = $Thing.PSpath
    Name = $Thing.name
  }
  $ht2 += $ht1
}

$ht2

请注意,我将 .path 更改为 .PSpath 以使该示例有效。请注意 $ht2 在循环之前被初始化为一个空数组。