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

Powershell 哈希表-组合未知数量的哈希表,powershell,hashtable,Powershell,Hashtable,我试图通过编程将未知数量的哈希表组合成一个更大的哈希表。每个表都有相同的键。我试图添加它,但它抛出了一个关于重复键的错误 ForEach ($Thing in $Things){ $ht1 = New-Object psobject @{ Path = $Thing.path Name = $Thing.name } $ht2 += $ht1 } 这就产生了错误 Item has already been added. Key in dictionary: 'Pat

我试图通过编程将未知数量的哈希表组合成一个更大的哈希表。每个表都有相同的键。我试图添加它,但它抛出了一个关于重复键的错误

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
}

如果已经存在具有相同键的元素,则确实要将元素添加到哈希表中。要克服这个问题,首先要看元素是否存在。这样,

if(-not $ht2.ContainsKey($thing.name)){
    $ht2.Add($thing.name, $thing.value)
}
if($ht2[$thing.name] -eq $null){
    $ht2.Add($thing.name, $thing.value)
}
也可以使用item属性
[]
进行检查,因为它为不存在的元素返回
$null
。这样,

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

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

1。使用静态方法
Add()
(第一项“wins”)

这已在中进行了解释,但简而言之:

如果在哈希表中添加一个项,而该项的键已经存在于哈希表中,
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。覆盖/添加而不考虑存在(最后一项“赢”)

您也可以选择“合并”条目,而无需进行如下检查:

    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]
        }
    }
这样,如果第一个哈希中已经存在条目,则其值将被第二个哈希中的值覆盖。 如果条目不存在,只需将其添加到第一个哈希表中

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

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

    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指出的哈希表数组。我最后的代码是:

#保留变量名称ht2,以明确其与原始问题的关系

$ht2 = @()

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

将我的评论转换为答案

您可能需要创建一个哈希表数组。数组中的每个项对于每个键都可以有自己的值。这种结构可以按照您在文章末尾的查询中指出的方式使用

试试这个:

$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在循环之前被初始化为空数组。

由于哈希表必须具有唯一的键,因此当存在重复键时,您不能将它们组合起来(如果它们的键不唯一,您会如何想象查找值?)?我只是注意到你的标题很混乱,因为你实际上没有添加,而是添加了一个。您可以只添加这样的集合:
$ht2+=New Object psobject@{Path=$Thing.Path Name=$Thing.Name}
,但同样,您应该避免使用
+=
这意味着最好也流式处理对象表的初始部分。换句话说,
$ht2
是哈希表还是对象集合?
$ht2.GetType().Name
(添加任何内容之前)返回什么<代码>哈希表或
对象[]
,或???最后一段代码显示了您打算如何使用这些数据。从那以后,我认为你真正想要的是一个关系,或者用powershell的术语来表示一个关系。我建议您使用哈希表数组。这样,每个哈希表可以表示一对,数组可以表示一个关系。您指的是对象数组。不是哈希表数组。还有,为什么不点击✓ 如果你发现它解决了你的问题,请点击左边的图标?@Theo我还不是100%清楚这两者之间的区别,所以我为这里的任何混淆道歉。我一直在读它。至于接受他的回答,最初只是一个评论。我看到他做了一个回答,并检查了一下。