Search code examples
powershellsortinghashtable

Sorting hash table (of hash tables)


I have hit a wall trying to get a hash table of hash tables to sort. It seems like the act of sorting is turning the hash table into something else, and I am unable to walk the new structure.

$mainHashTable = @{}
$mainHashTable.Add('B', @{'one'='B1'; 'two'='B2'; 'three'='B3'})
$mainHashTable.Add('D', @{'one'='D1'; 'two'='D2'; 'three'='D3'})
$mainHashTable.Add('A', @{'one'='A1'; 'two'='A2'; 'three'='A3'})
$mainHashTable.Add('C', @{'one'='C1'; 'two'='C2'; 'three'='C3'})

CLS
$mainHashTable
foreach ($hashtable in $mainHashTable.keys) {

    foreach ($itemKey in $mainHashTable.$hashtable.keys) {
        Write-Host "$itemKey $($mainHashTable.$hashtable.$itemKey)!"
    }
}
Write-Host
$sortedHashTable = $mainHashTable.GetEnumerator() | sort-object -property name
$sortedHashTable
foreach ($hashtable_S in $sortedHashTable.keys) {
    foreach ($itemKey_S in $sortedHashTable.$hashtable_S.keys) {
        Write-Host "$itemKey_S $($sortedHashTable.$hashtable_S.$itemKey2)!"
    }
}

The two lines that dump $mainHashTable & $sortedHashTable to the console look like everything is fine. But the second loop set does nothing. I have tried casting like this

$sortedHashTable = [hashtable]($mainHashTable.GetEnumerator() | sort-object -property name)

and that just throws the error

Cannot convert the "System.Object[]" value of type "System.Object[]" to type "System.Collections.Hashtable".

So, is there some way to convert the system object to a hash table, so the loop structure works on the sorted results? Or am I better off learning to walk the structure of the System.Object? And (academically perhaps), is there a way to sort a hash table and get back a hash table?


Solution

  • What you're currently doing is splitting the hashtable into a list of separate entries (via .GetEnumerator()) and then sorting that - so you end up with $sortedHashTable being just an array of key/value pair objects, sorted by key, not an actual [hashtable].

    is there a way to sort a hash table and get back a hash table?

    No - you can't "sort a hash table" inline, because hashtables do not retain any guaranteed key order.

    The way to go here is to copy the entries to an ordered dictionary, in order:

    $sortedHashTable = [ordered]@{}
    
    # Sort the keys, then insert into our ordered dictionary
    foreach($key in $mainHashTable.Keys |Sort-Object){
        $sortedHashTable[$key] = $mainHashTable[$key]
    }