• Aucun résultat trouvé

Creating and inspecting hashtables

Dans le document Bruce PayetteSECOND EDITION (Page 116-119)

Working with types

3.3 C OLLECTIONS : DICTIONARIES AND HASHTABLES

3.3.1 Creating and inspecting hashtables

In PowerShell, you use hash literals to create a hashtable inline in a script. Here’s a simple example:

PS (26) > $user = @{ FirstName = "John"; LastName = "Smith";

>> PhoneNumber = "555-1212" } PS (27) > $user

Key Value --- ---LastName Smith FirstName John PhoneNumber 555-1212

This example created a hashtable that contains three key-value pairs. The hashtable starts with the token @{ and ends with }. Inside the delimiters, you define a set of key-value pairs where the key and value are separated by an equals sign (=). Formally, the syntax for a hash literal is

<hashLiteral> = '@{' <keyExpression> '=' <pipeline> [ <separator>

<keyExpression> '=' <pipeline> ] * '}'

Now that you’ve created a hashtable, let’s see how you can use it. PowerShell allows you to access members in a hashtable in two ways—through property notation and through array notation. Here’s what the property notation looks like:

PS (3) > $user.firstname John

PS (4) > $user.lastname Smith

This notation lets you treat a hashtable like an object. This access method is intended to facilitate the use of hashtables as a kind of lightweight data record. Now let’s look at using the array notation:

PS (5) > $user["firstname"]

John

PS (6) > $user["firstname","lastname"]

John Smith

Property notation works pretty much the way you’d expect; you specify a property name and get the corresponding value back. Array notation, on the other hand, is more interesting. In the second command in the example, you provided two keys and got two values back.

Here’s an example that shows some additional features of the underlying hashtable object. The underlying object for PowerShell hashtables is the .NET type System.Collections.Hashtable. This type has a number of properties and meth-ods that you can use. One of these properties is keys. This property will give you a list of all the keys in the hashtable:

PS (7) > $user.keys LastName

FirstName PhoneNumber

In the array access notation, you can use keys to get a list of all the values in the table:

PS (8) > $user[$user.keys]

Smith John 555-1212

NOTE A more efficient way to get all of the values from a hashtable is to use the Valuesproperty. The point of this example is to demon-strate how you can use multiple indexes to retrieve the values based on a subset of the keys.

You might have noticed that the keys property didn’t return the keys in alphabetical order. This is because of the way hashtables work—keys are randomly distributed in the table to speed up access. If you do need to get the values in alphabetical order, here’s how you can do it:

PS (10) > $user.keys | sort-object FirstName

LastName PhoneNumber

COLLECTIONS: DICTIONARIESANDHASHTABLES 87 The Sort-Object (or just sort) cmdlet sorts the keys into alphabetical order and returns a list. Use this list to index the table:

PS (11) > $user[[string[]] ($user.keys | sort)]

John Smith 555-1212

You’ll notice something funny about the last example: we had to cast or convert the sorted list into an array of strings. This is because the hashtable keys mechanism expects strings, not objects, as keys. There’s much more on casts later in this chapter.

A digression: sorting, enumerating, and hashtables

Let’s digress for a second and address a question that comes up sometimes when peo-ple, especially .NET programmers, first encounter hashtables in PowerShell. The question is, “Are hashtables collections or scalar objects?” From the .NET perspective, they’re enumerable collections just like arrays except they contain a collection of key-value pairs. However, and this is important, PowerShell treats hashtables like scalar objects. It does this because, in scripting languages, hashtables are commonly used as on-the-fly structures or data records. Using hashtables this way, you don’t have to pre-define the fields in a record; you just make them up as you go. If PowerShell treated hashtables as enumerable collections by default, this wouldn’t be possible because every time you passed one of these “records” into a pipeline, it would be broken up into a stream of individual key-value pairs and the integrity of the original table would be lost.

This causes the most problems for people when they use hashtables in the foreach statement. In a .NET language like C#, the foreach statement iterates over all the pairs. In PowerShell, the foreach loop will run only once because the hashtable isn’t considered an enumerable, at least not by default. So, if you do want to iterate over the pairs, you’ll have to call the GetEnumerator() method yourself.

This looks like

PS (12) > $h = @{a=1; b=2; c=3}

PS (13) > foreach ($pair in $h.GetEnumerator())

>> {

>> $pair.key + " is " + $pair.value

>> }

>>

a is 1 b is 2 c is 3

In each iteration, the next pair is assigned to $pair and processing continues.

A significant part of the reason this behavior confuses people is that when Power-Shell displays a hashtable, it uses enumeration to list the key-value pairs as part of the presentation. The result is that there’s no visible difference between when you call

GetEnumerator() in the foreach loop and when you don’t. Let’s look at this. First, the no GetEnumerator() case:

PS (14) > foreach ($pair in $h) { $pair } Name Value ---- ---a 1 b 2 c 3

Now call GetEnumerator() in the loop:

PS (15) > foreach ($pair in $h.GetEnumerator()) { $pair } Name Value

---- ---a 1 b 2 c 3

As you can see, the output is identical in both cases. This is desirable in the sense that it’s a good way to present a hashtable and doesn’t require effort from the user to do this. On the other hand, it masks the details of what’s really going on. As always, it’s difficult to serve all audiences perfectly.

Another aspect of the hashtable collection question is that people want to be able to “sort” a hashtable the way you’d sort a list of numbers. In the case of a hashtable, this usually means that the user wants to be able to control the order in which keys will be retrieved from the hashtable. Unfortunately this can’t work because the default hashtable object that PowerShell uses has no way to store any particular key ordering in the table. The keys are just stored in random order, as you saw earlier in this section. If you want to have an ordered dictionary, you’ll have to use a different type of object, such as

[Collections.Generic.SortedDictionary[object,object]]

This is a sorted generic dictionary (we’ll get to type literals and generics later in this chapter). And now, back to our regularly scheduled topic.

Dans le document Bruce PayetteSECOND EDITION (Page 116-119)