Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Union and Intersection of Hashtables in PowerShell

Tags:

powershell

In Union and Intersection in PowerShell? cool one-liners for set operations of arrays are described.

I want to do this with hashtables and have a solution using the keysets of the dictionaries. To extend then to the values, I use for-loops to iterate over the intersection of the keys and copy the values over to new result-hashtables. This looks not clean.

Further research showed solutions with GetEnumerator which is also not clean IMHO.

How can I replace the bloated for loops or enumerators by concise and nice one-liners?

Source code below:

http://paste.ubuntu.com/13362425/

# import csv
$a = Import-Csv -Path A.csv -Delimiter ";" -Header "Keys","Values"
$b = Import-Csv -Path B.csv -Delimiter ";" -Header "Keys","Values"

# Make nice hashtables for further use
$AData = @{}
foreach($r in $a)
  { $AData[$r.Keys] = $r.Values }
$BData = @{}
foreach($r in $b)
  { $BData[$r.Keys] = $r.Values }

# Set difference to find missing entries
$MissingA = $AData.Keys | ?{-not ($BData.Keys -contains $_)}

# I don't know how to do set-operations on hashtables yet. So use keysets and copy data (lame!)
$MissingAData = @{}
foreach($k in $MissingA)
{
    $MissingAData[$k] = $AData[$k]
}

# Intersection
$Common = $AData.Keys | ?{$BData.Keys -contains $_}
like image 236
Bastl Avatar asked Nov 20 '15 09:11

Bastl


1 Answers

You can use the same technique as for lists, but use the hash table keys, as you indicate in the OP.

For union and intersection you have an additional problem. Of the keys in common between the two hash tables, which value will you keep? Assume you will always keep the value in the first hash table. Then:

# need clone to prevent .NET exception of changing hash while iterating through it
$h1clone = $hash1.clone()

# intersection
$h1clone.keys | ? {$_ -notin $hash2.keys} | % {$hash1.remove($_)}

# difference: $hash1 - $hash2
$h1clone.keys | ? {$_ -in $hash2.keys}    | % {$hash1.remove($_)}

# union. Clone not needed because not iterating $hash1
$hash2.keys   | ? {$_ -notin $hash1.keys} | % {$hash1[$_] = $hash2[$_]}

Or you could do this which avoids the clone and creates a new hash table

# intersection
$newHash = @{}; $hash1.keys | ? {$_ -in $hash2.keys} | % {$newHash[$_] = $hash1[$_]}

# difference: $hash1 - $hash2
$newHash = @{}; $hash1.keys | ? {$_ -notin $hash2.keys} | % {$newHash[$_] = $hash1[$_]}
like image 184
Χpẘ Avatar answered Oct 16 '22 09:10

Χpẘ