Working with Hash Tables
In last week’s Windows PowerShell Tip we introduced you to the .NET Framework class System.Collections.ArrayList, positioning this class as an alternative to the array class built into Windows PowerShell. (Why do you even needan alternative to the array class built into Windows PowerShell? Well, for one thing, the ArrayList class makes it easy to remove items from the array, something that’s nearly impossible to do otherwise.) In that same column we promised that, this week, we’d discuss another alternative to the generic Windows PowerShell array: the hash table. Well, never let it be said that the Scripting Guys don’t always keep their promises.
Note. OK, so technically we don’talways keep our promises. We just never want that to be said.
Although the term
hash tablemight be new to many of you, there’s a good chance
that you’re familiar with the concept; after all, a hash table is
simply a collection of name-value pairs, very much like the
FileSystemObject’s
Dictionaryobject. For example, suppose you have a collection
of US states and their capitals. Each state has one – and only one
– capital (e.g., the state capital of
Note. Yes, we know: we didn’t really go over the concept of key-value pairs, did we? But that’s OK. The Dictionary object explanation found in the Microsoft Windows 2000 Scripting Guide applies equally well to the Windows PowerShell hash table.
But enough with the talk; let’s see some code. Suppose you really wouldlike a hash table containing a list of US states and their capitals; how would you go about creating such a thing? Well, here’s one way:
$states = @{"
Granted this is a bit cryptic-looking at least at first glance; fortunately, however, it’s nowhere near as complicated as it might appear. All we’re doing here is assigning three sets of key-value pairs to a hash table named $states. As you can see, the syntax for creating a hash table involves using an at sign (@) followed by a pair of curly braces.
Note. The @ symbol is know as the at sign only in English; in other languages , it’s known as way cooler things, like maggot, monkey’s tail, and pickled herring.
So what goes inside
those curly braces? Well, that’s where we specify the key-value
pairs, using the syntax
key = value; for example,
"
And what will the variable $states be equal to after we issue our hash table command? Why, this, of course:
Name
Value
----
-----
That’s pretty good,
except for one thing: our hash table is far from complete. (After
all, we only list 3
$states.Add("
Note. Yes, yes, we know:
Needless to say,
there’s nothing too fancy going on here: we simply call the
Addmethod, passing this method two parameters: the new key (
"
Name
Value
----
-----
Incidentally, that’s a good observation: you never know exactly where a new entry will appear in the hash table. In this case, for example, our new entry somehow became item 2 in a 4-item table. But that’s OK; before we go we’ll show you how to test for the existence of a key or a value regardless of their position in the hash table. And, just for the heck of it, we’ll show you how to sort the table as well.
But first things
first. As the tidal wave of emails and phone calls has made very
clear, the state capital of
Well, one thing we
coulddo is simply remove the offending item. Want to get rid
of the key-value pair for
$states.Remove("
Just to be on the safe side, let’s take a look at the value of $states:
Name
Value
----
-----
That’s better, isn’t it?
Alternatively, we
could have used the
Set_Itemmethod to change the value assigned to
$states.Set_Item("
Run that command and then take a look at the value of $states; it should be equal to the following:
Name
Value
----
-----
Incidentally, the
Set-Item method has a corollary method named
Get_Item; this method enables us to retrieve the value
associated with a specific item in the hash table. Not sure which
city is the capital of
$states.Get_Item("
Now, suppose that
the state of
Fortunately, you can
use the
ContainsKeyand the
ContainsValuemethods to search for items in a hash table.
Need to know if an item named
$states.ContainsKey("
This method returns
True if it finds an item named
$states.ContainsValue("
Note. If you just need to know how many items are in a hash table you can simply report back the value of the Countproperty: $states.Count.
Last, but surely not least, let’s talk about sorting a hash table. This can be a little tricky; this command will notwork:
$states | Sort-Object
Why not? Well, in the preceding command the hash table is sent as a single object; thus there’s nothing for the Sort-Objectcmdlet to sort. If we want to sort a hash table by Name we need to use the GetEnumeratormethod, which effectively sends each entry in the hash table across the pipeline as a separate object:
$states.GetEnumerator() | Sort-Object Name
Which, in turn, gives us output like this:
Name
Value
----
-----
Here’s a similar command, except that this one sorts the hash table by Value and (just because we wanted to show off a little) in descending order to boot:
$states.GetEnumerator() |
Sort-Object Value -descending
And here’s what the output of thatcommand looks like: