development, documentation, powershell,

Merging dictionaries within powershell

agowa338 agowa338 Sep 01, 2020 · 3 mins read
Share this

I needed to join dictionaries from within a list together, so that they become one whole dictionary.
First I thought it may be a trivial task. Than I used google and realized, that everything on the first page was just wrong or impracticable for lists with unknown size.

What I found by googling, was stuff like:

$a = @{"foo"=1}
$b = @{"bar"=2}
$c = @($a,$b) | ForEach-Object {$_}
and
$a = @{"foo"=1}
$b = @{"bar"=2}
$c = $a + $b
The console output of $c will look identical for both:
Name                           Value
----                           -----
foo                            1
bar                            2
But the issue is with the data structure. This becomes a problem when we would like to access the data.

E.g.

$c['foo']

Will output $null for the first example and "2" for the 2nd. But why is this?
Lets convert it to json (without piping, this is important) to visualize the data structure:

ConvertTo-Json -InputObject $c

which outputs for the first case:

[
  {
    "foo": 1
  },
  {
    "bar": 2
  }
]

and for the 2nd what we originally expected:

{
  "bar": 2,
  "foo": 1
}

So now we know that the first one did not join the dictionaries, but warped them into a list. As we originally looked for a solution to join a list of dictionaries, this is not helpful. (Note: From now on $c is the output from the first example, as it is the same as my original input). The 2nd one however looks helpful, but has two issues:

  1. It only works if we know how many elements we have (hard coded element count)
  2. It copies the list once for each element we want to add to it.

So let's address these issues:

  1. For the 1st one something like this will do the trick:
    $c | ForEach-Object -Begin {[Hashtable]$aa = @{}} -Process {$aa += $_} -End {$aa} | ConvertTo-Json
  2. But for the 2nd we need something a bit more advanced like
    $c | ForEach-Object -Begin {[Hashtable]$aa = @{}} -Process {foreach($element in ($_.GetEnumerator())) {$aa.Add($element.Key,$element.Value)}} -End {$aa} | ConvertTo-Json

agowa338
Written by agowa338