Merging hashtables in PowerShell: how?

前端 未结 12 1913
猫巷女王i
猫巷女王i 2021-01-07 18:26

I am trying to merge two hashtables, overwriting key-value pairs in the first if the same key exists in the second.

To do this I wrote this function which first remo

相关标签:
12条回答
  • 2021-01-07 19:16

    Here is a function version that doesn't use the pipeline (not that the pipeline is bad, just another way to do it). It also returns a merged hashtable and leaves the original unchanged.

    function MergeHashtable($a, $b)
    {
        foreach ($k in $b.keys)
        {
            if ($a.containskey($k))
            {
                $a.remove($k)
            }
        }
    
        return $a + $b
    }
    
    0 讨论(0)
  • 2021-01-07 19:17

    I see two problems:

    1. The open brace should be on the same line as Foreach-object
    2. You shouldn't modify a collection while enumerating through a collection

    The example below illustrates how to fix both issues:

    function mergehashtables($htold, $htnew)
    {
        $keys = $htold.getenumerator() | foreach-object {$_.key}
        $keys | foreach-object {
            $key = $_
            if ($htnew.containskey($key))
            {
                $htold.remove($key)
            }
        }
        $htnew = $htold + $htnew
        return $htnew
    }
    
    0 讨论(0)
  • 2021-01-07 19:17

    I wanted to point out that one should not reference base properties of the hashtable indiscriminately in generic functions, as they may have been overridden (or overloaded) by items of the hashtable.

    For instance, the hashtable $hash=@{'keys'='lots of them'} will have the base hashtable property, Keys overridden by the item keys, and thus doing a foreach ($key in $hash.Keys) will instead enumerate the hashed item keys's value, instead of the base property Keys.

    Instead the method GetEnumerator or the keys property of the PSBase property, which cannot be overridden, should be used in functions that may have no idea if the base properties have been overridden.

    Thus, Jon Z's answer is the best.

    0 讨论(0)
  • 2021-01-07 19:17

    I just wanted to expand or simplify on jon Z's answer. There just seems to be too many lines and missed opportunities to use Where-Object. Here is my simplified version:

    Function merge_hashtables($htold, $htnew) {
        $htold.Keys | ? { $htnew.ContainsKey($_) } | % {
            $htold.Remove($_)
        }
        $htold += $htnew
        return $htold
    }
    
    0 讨论(0)
  • 2021-01-07 19:18

    The open brace has to be on the same line as ForEach-Object or you have to use the line continuation character (backtick).

    This is the case because the code within { ... } is really the value for the -Process parameter of ForEach-Object cmdlet.

    -Process <ScriptBlock[]> 
    Specifies the script block that is applied to each incoming object.
    

    This will get you past the current issue at hand.

    0 讨论(0)
  • 2021-01-07 19:24

    I just needed to do this and found this works:

    $HT += $HT2
    

    The contents of $HT2 get added to the contents of $HT.

    0 讨论(0)
提交回复
热议问题