Introduction
PowerShell provides the += operator to add one hash table to another hash table. By default this operation will result in an error, if both hash tables have at least one key that is common in both collections. In some cases you may want to have a more granular control. For example, you don't want to get an error, if not only the key, but also the value is common in both collections. On top of this somebody might want to allow an overwrite, if the key and the value are going to be identical as result of the merge. This could be useful, if the hash table is used as template for replacing strings. Updating the master table by adding a key value pair that refers to the same string would mean to exclude this particular replacement pair from the replacement transactions.
Figure 1: Key Value Pairs
Default operator+= implementation
1: $target = @{} 2: $source = @{} 3:
4: $target.a = "aaaaa"
5: $target.b = "bbbbb"
6: $target.c = "ccccc"
7: $target.d = "ddddd"
8:
9: $source.a = "aa"
10: $source.b = "bb"
11: $source.c = "ccccc"
12: $source.d = "dd"
13: $source.e = "ee"
14: $source.f = "ff"
15:
16: #------------------------- Standard Merge ----------------------------
17:
18: # Keys a, b, c, d are both in hash tables $source and $target. The merge will fail
19: $target += $source
20:
21: #OUTPUT
22: #The '+=' operator failed: Item has already been added. Key in dictionary: 'a' Key being added: 'a'.
23: #At line 21, position 11
24: #$target += $source
Customized merge implementation
Duplicate pairs allowed
1: #------------------------- Manual Merge no ambiguity ------------------
2:
3: $target = @{} 4: $source = @{} 5:
6: $target.a = "aaaaa"
7: $target.b = "bbbbb"
8: $target.c = "ccccc"
9: $target.d = "ddddd"
10:
11: $source.a = "aaaaa"
12: $source.b = "bbbbb"
13: $source.c = "ccccc"
14: $source.d = "ddddd"
15: $source.e = "ee"
16: $source.f = "ff"
17:
18: # Allows merges if identical value-key pairs are in $source and $target in this example they
19: # a = "aaaaa"
20: # b = "bbbbb"
21: # c = "ccccc"
22: # d = "ddddd"
23:
24: $Source.GetEnumerator() | ForEach-Object `
25: { ` 26: if(!$Target.ContainsKey($_.key))
27: { ` 28: "`$Source does not contain Key $($_.Key)"; $Target[$_.key] = $_.value `
29: } `
30: else `
31: { ` 32: if($Target[$_.key] -ne $Source[$_.key]) `
33: { ` 34: throw "FATAL ERROR while merging tables! REASON: Ambigous key-value mapping! $($_.Key)=$($Target[$_.key]) and $($_.Key)=$($Source[$_.key])" `
35: } `
36: } `
37: }
38:
39: $target
40:
41: #OUTPUT
42: #$Source does not contain Key f
43: #$Source does not contain Key e
44: #
45: #Name Value
46: #---- -----
47: #e ee
48: #a aaaaa
49: #f ff
50: #b bbbbb
51: #d ddddd
52: #c ccccc
Ambiguous pairs cause error
1: #------------------------- Manual merge with ambiguity --------------------------
2:
3: $target = @{} 4: $source = @{} 5:
6: $target.a = "aa"
7: $target.b = "bb"
8: $target.c = "ccccc"
9: $target.d = "ddddd"
10:
11: $source.a = "aaaaa"
12: $source.b = "bbbbb"
13: $source.c = "ccccc"
14: $source.d = "ddddd"
15: $source.e = "ee"
16: $source.f = "ff"
17:
18: # Fails if merge encounters ambiguity, a="aa" and a="aaaaa" also b="bb" and b="bbbbb"
19:
20: $Source.GetEnumerator() | ForEach-Object `
21: { ` 22: if(!$Target.ContainsKey($_.key))
23: { ` 24: "`$Source does not contain Key $($_.Key)"; $Target[$_.key] = $_.value `
25: } `
26: else `
27: { ` 28: if($Target[$_.key] -ne $Source[$_.key]) `
29: { ` 30: throw "FATAL ERROR while merging tables! REASON: Ambigous key-value mapping! $($_.Key)=$($Target[$_.key]) and $($_.Key)=$($Source[$_.key])" `
31: } `
32: } `
33: }
34:
35: $target
36:
37: #OUTPUT
38: #FATAL ERROR while merging tables! REASON: Ambigous key-value mapping! a=aa and a=aaaaa
39: #At line 19, position 98
Download
The PowerShell script can be downloaded here: MergeStudy.zip
Ausblick
Now that I have a custom solution for merging hash tables, I would like to use this to override the default behavior of the += operator of the hash table object. I think it should be possible using the one of the member extension objects used by PSObject. Ideally I would like to have this behavior be specialized based on the key and value data types. Next I am gong to research the operator overriding and specialization in generics in PowerShell and .NET.