Tome's Land of IT

IT Notes from the Powertoe – Tome Tanasovski

Combining Objects Efficiently – Use a Hash Table to Index a Collection of Objects

With objects objects everywhere it may not seem apparent, but hash tables are still needed.  When the PowerShell mind sets to work it can be very easy to use where and selects everywhere to get you what you want, but that may not always be the best way.  Hash tables provide you an easy way to index a collection of objects.

Case:  Lets’s say you have a collection of objects with a path property, but there is another collection of objects that correlates the path to a share.  This collection may be a lookup table that is imported from a CSV file.  How can we combine the properties of the objects together so that we add the value of the lookup table to the property of the original collection of objects.

Here’s some sample code to create the two collections with dummy data:

$objects = (0..$numberofobjects) |% {
    New-Object psobject -Property @{'Name'="object$_";'Path'="Path$_"}
}
$lookupobjects = (0..$numberofobjects) |% {
    New-Object psobject -Property @{'Path'="Path$_";'Share'="Share$_"}
}

At first glance you may consider something like this to add the property from one object to your existing objects:

foreach ($object in $objects) {
        $object |Add-Member NoteProperty -Name Share -Value ($lookupobjects|?{$_.Path -eq $object.Path} |select -First 1 -ExpandProperty share)
}

The code will work, but it will be excrutiatingly slow.  That’s where our friend the hash table comes into play.  We know that we are going to go through each of our $objects and look at our $lookupobjects to find a matching path.  We know that the path is unique in the $lookupobjects.  It would be better to have a way to access the $lookupobjects via an indexed path property.  Using a hash table creates this index for us.  Here’s a sample bit of code that will create the hash table from our $lookupobjects:

$hash = @{}
foreach ($obj in $lookupobjects) {
    $hash.($obj.Path) = $obj
}

With that done we can then directly call something in a path by using $hash.pathname. Here’s how you would use it to do exactly what we did in the first example:

foreach ($object in $objects) {
    $object |Add-Member NoteProperty -Name Share -Value ($hash.($object.path)).share
}

You can see the difference in speed when you put it all together. The object method takes 167 seconds on my computer while the hash table method will take under a second to build the hash table and then do the lookup:

$numberofobjects = 1000

$objects = (0..$numberofobjects) |% {
    New-Object psobject -Property @{'Name'="object$_";'Path'="Path$_"}
}
$lookupobjects = (0..$numberofobjects) |% {
    New-Object psobject -Property @{'Path'="Path$_";'Share'="Share$_"}
}

$method1 = {
    foreach ($object in $objects) {
        $object |Add-Member NoteProperty -Name Share -Value ($lookupobjects|?{$_.Path -eq $object.Path} |select -First 1 -ExpandProperty share)
    }
}
Measure-Command $method1 |select totalseconds

$objects = (0..$numberofobjects) |% {
    New-Object psobject -Property @{'Name'="object$_";'Path'="Path$_"}
}
$lookupobjects = (0..$numberofobjects) |% {
    New-Object psobject -Property @{'Path'="Path$_";'Share'="Share$_"}
}

$method2 = {
    $hash = @{}
    foreach ($obj in $lookupobjects) {
        $hash.($obj.Path) = $obj.share
    }
    foreach ($object in $objects) {
        $object |Add-Member NoteProperty -Name Share -Value ($hash.($object.path)).share
    }
}
Measure-Command $method2 |select totalseconds

Nuff said!

About these ads

2 responses to “Combining Objects Efficiently – Use a Hash Table to Index a Collection of Objects

  1. jrich July 6, 2011 at 8:07 am

    great method! thanks for the post

  2. Mark Seymour July 31, 2013 at 4:55 am

    It is a great example of the power of hash tables. Also the use of Measure-Command is neat.

    One amendment to your script is for the Method 2. The following line: –

    $object |Add-Member NoteProperty -Name Share -Value ($hash.($object.path)).share

    This should read : –

    $object |Add-Member NoteProperty -Name Share -Value ($hash.($object.path))

    As the Path is the Hash table “key” and the Share is the “Value”.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 31 other followers

%d bloggers like this: