Hashtables and key order

36,282

Solution 1

There is no built-in solution in PowerShell V1 / V2. You will want to use the .NET System.Collections.Specialized.OrderedDictionary:

$order = New-Object System.Collections.Specialized.OrderedDictionary
$order.Add("Switzerland", "Bern")
$order.Add("Spain", "Madrid")
$order.Add("Italy", "Rome")
$order.Add("Germany", "Berlin")


PS> $order

Name                           Value
----                           -----
Switzerland                    Bern
Spain                          Madrid
Italy                          Rome
Germany                        Berlin

In PowerShell V3 you can cast to [ordered]:

PS> [ordered]@{"Switzerland"="Bern"; "Spain"="Madrid"; "Italy"="Rome"; "Germany"="Berlin"}

Name                           Value
----                           -----
Switzerland                    Bern
Spain                          Madrid
Italy                          Rome
Germany                        Berlin

Solution 2

You can use an ordered dictionary instead:

Like this:

$list = New-Object System.Collections.Specialized.OrderedDictionary
$list.Add("Switzerland", "Bern")
$list.Add("Spain", "Madrid")
$list.Add("Italy", "Rome")
$list.Add("Germany", "Berlin")
$list

Solution 3

You can give one sequential key as you add elements:

$hashtable = @{}
$hashtable[$hashtable.count] = @("Switzerland", "Bern")
$hashtable[$hashtable.count] = @("Spain", "Madrid")
$hashtable[$hashtable.count] = @("Italy", "Rome")
$hashtable[$hashtable.count] = @("Germany", "Berlin")
$hashtable

Then, you can get elements sorted by the key:

echo "`nHashtable keeping the order as they were added"
foreach($item in $hashtable.getEnumerator() | Sort Key)
{
    $item
}

Solution 4

Here is a simple routine that works for me.

function sortedKeys([hashtable]$ht) {
  $out = @()
  foreach($k in $ht.keys) {
    $out += $k
  }
  [Array]::sort($out)
  return ,$out
}

and the call to use it

forEach($k in (& sortedKeys $ht)) {
  ...
}

Solution 5

The PowerShell 1 way is to add a hashtable member to retain the add order. There is no need to use System.Collections.Specialized.OrderedDictionary:

$Hash = New-Object PSObject                                       
$Hash | Add-Member -MemberType NoteProperty -Name key1 -Value val1
$Hash | Add-Member -MemberType NoteProperty -Name key2 -Value val2
$Hash | Add-Member -MemberType NoteProperty -Name key3 -Value val3
Share:
36,282
Philipp
Author by

Philipp

Updated on February 01, 2020

Comments

  • Philipp
    Philipp over 4 years

    Is there a way to keep the order of keys in a hashtable as they were added? Like a push/pop mechanism.

    Example:

    $hashtable = @{}
    
    $hashtable.Add("Switzerland", "Bern")
    $hashtable.Add("Spain", "Madrid")
    $hashtable.Add("Italy", "Rome")
    $hashtable.Add("Germany", "Berlin")
    $hashtable
    

    I want to retain the order in which I've added the elements to the hashtable.

  • Philipp
    Philipp about 11 years
    Thanks for the answers! I knew the PS v3 [ordered] but I must use PS 2.0
  • Adi Inbar
    Adi Inbar over 10 years
    But that's not a hashtable, it's a PSCustomObject. Not the same thing, even if you name the variable "$Hash". ;) An OrderedDictionary functions just like a hashtable for all practical purposes that I've tried.
  • Elletlar
    Elletlar over 5 years
    Welcome to Stack Overflow. While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value.How to Answer. Thanks!
  • Peter Mortensen
    Peter Mortensen over 5 years
    But the question was about keeping the order in which the hash was added to, not sorting by keys. How does this answer the question?
  • Steve Pritchard
    Steve Pritchard about 5 years
    Peter, you are correct. I was confused and thought Ordered dictionary was like a Java TreeMap not a LinkedHashMap. Thanks for the clarification.
  • user1708042
    user1708042 over 3 years
    Thanks, what to say: strange implementation, I see no reason for that implementation as being the default. You need it unodered for raw speed? Do a custom class for that and let the base be, as most would expcet, ordered with the insert order.
  • ruffin
    ruffin over 2 years
    Note that you also have to use this type (System.Collections.Specialized.OrderedDictionary) for the parameter if you want to pass your ordered hash to a function. You cannot use a flavor of the [ordered][hash] shortcut as a param typing, and must use the full type. You can pass as a [hash] parameter, but you lose the ordering (since it's passed as the less specific extended hash type; more at that link), which is likely undesirable. 😉