0

I cannot figure out why the loop below is return null keys. I think $hashSorted is not of type Hashtable; so how do I force it to be? Thinking now I need a deep/copy? I just want to sort my hashtable and put it into another hashtable.

This might be a dup of: Sort Hashtable and assign it to a new variable in Powershell My original questiion was why the keys were null when doing the loop. Then I realized it probably wasn't a hashtable. Still trying the answers there.

Reference: How can I enumerate a hashtable as key-value pairs / filter a hashtable by a collection of key values

cls
$hashFilesAndSizes = @{}
$hashSorted = @{}
$hashFilesAndSizes.Add("file1.txt",1000)
$hashFilesAndSizes.Add("file2.txt",200)
$hashFilesAndSizes.Add("file3.txt",750)
$hashFilesAndSizes.GetEnumerator() | sort value  #Displays sorted hash table 

Write-Host "Second Try - put in another hashtable"
$hashSorted = $hashFilesAndSizes.GetEnumerator() | sort value  #put into a new variable 
Write-Host "Original variable in original Order" 
$hashFilesAndSizes
Write-Host "Sorted" 
$hashSorted #show results 

Write-Host "Why loop has null keys?"

  foreach($key in $hashSorted.Keys) 
   {
      Write-Host "Key=$key" 
      #if (-not ([string]::IsNullOrEmpty($key)))
      #{
          $keyPadded = $key.PadRight(50," ")
          $fileSize = $hashSorted[$key] 
          $fileSizeFormatted = $fileSize.ToString("000,000")
          Write-Host "$keyPadded  size=$fileSizeFormatted "
      #}
   }

Write-Host "Test with enumerator"

  foreach($item in $hashSorted.GetEnumerator()) 
   {
      $key = $hashSorted.Key 
      Write-Host "Key=$key" 
      #if (-not ([string]::IsNullOrEmpty($key)))
      #{
          $keyPadded = $key.PadRight(50," ")
          $fileSize = $hashSorted.Value
          $fileSizeFormatted = $fileSize.ToString("000,000")
          Write-Host "$keyPadded  size=$fileSizeFormatted "
      #}
   }

Results:

> Name                           Value                                  
> 
> ----                           -----                                                                                                                     file2.txt                      200                                    
> file3.txt                      750                                    
> file1.txt                      1000                                   
> Second Try - put in another hashtable Original variable in original
> Order file3.txt                      750                              
> file1.txt                      1000                                   
> file2.txt                      200                                    
> Sorted file2.txt                      200                             
> file3.txt                      750                                    
> file1.txt                      1000                                   
> Why loop has null keys? Key= You cannot call a method on a null-valued
> expression. At C:\Scripts\HashTableSortTest.ps1:23 char:37
> +           $keyPadded = $key.PadRight <<<< (50," ")
>     + CategoryInfo          : InvalidOperation: (PadRight:String) [], RuntimeException
>     + FullyQualifiedErrorId : InvokeMethodOnNull   Index operation failed; the array index evaluated to null. At
> C:\Scripts\HashTableSortTest.ps1:24 char:35
> +           $fileSize = $hashSorted[ <<<< $key] 
>     + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
>     + FullyQualifiedErrorId : NullArrayIndex   You cannot call a method on a null-valued expression. At
> C:\Scripts\HashTableSortTest.ps1:25 char:50
> +           $fileSizeFormatted = $fileSize.ToString <<<< ("000,000")
>     + CategoryInfo          : InvalidOperation: (ToString:String) [], RuntimeException
>     + FullyQualifiedErrorId : InvokeMethodOnNull
>     size=  
>Test with enumerator Key= You cannot call a method on a null-valued expression. At C:\Scripts\HashTableSortTest.ps1:38 char:37
> +           $keyPadded = $key.PadRight <<<< (50," ")
>     + CategoryInfo          : InvalidOperation: (PadRight:String) [], RuntimeException
>     + FullyQualifiedErrorId : InvokeMethodOnNull   You cannot call a method on a null-valued expression. At
> C:\Scripts\HashTableSortTest.ps1:40 char:50
> +           $fileSizeFormatted = $fileSize.ToString <<<< ("000,000")
>     + CategoryInfo          : InvalidOperation: (ToString:String) [], RuntimeException
>     + FullyQualifiedErrorId : InvokeMethodOnNull
>     size=  Key= You cannot call a method on a null-valued expression. At C:\Scripts\HashTableSortTest.ps1:38 char:37
> +           $keyPadded = $key.PadRight <<<< (50," ")
>     + CategoryInfo          : InvalidOperation: (PadRight:String) [], RuntimeException
>     + FullyQualifiedErrorId : InvokeMethodOnNull   You cannot call a method on a null-valued expression. At
> C:\Scripts\HashTableSortTest.ps1:40 char:50
> +           $fileSizeFormatted = $fileSize.ToString <<<< ("000,000")
>     + CategoryInfo          : InvalidOperation: (ToString:String) [], RuntimeException
>     + FullyQualifiedErrorId : InvokeMethodOnNull
>     size=  Key= You cannot call a method on a null-valued expression. At C:\Scripts\HashTableSortTest.ps1:38 char:37
> +           $keyPadded = $key.PadRight <<<< (50," ")
>     + CategoryInfo          : InvalidOperation: (PadRight:String) [], RuntimeException
>     + FullyQualifiedErrorId : InvokeMethodOnNull   You cannot call a method on a null-valued expression. At
> C:\Scripts\HashTableSortTest.ps1:40 char:50
> +           $fileSizeFormatted = $fileSize.ToString <<<< ("000,000")
>     + CategoryInfo          : InvalidOperation: (ToString:String) [], RuntimeException
>     + FullyQualifiedErrorId : InvokeMethodOnNull
>     size=
NealWalters
  • 17,197
  • 42
  • 141
  • 251
  • 2
    Hashtables are never guaranteed to honor ordering. Sorting a hashtable is nonsensical. Use an ordered collection of some sort if order is important. – EBGreen Jun 19 '18 at 14:55
  • [Hash table](https://en.wikipedia.org/wiki/Hash_table) keys are not ordered because they are optimized for a [binary search](https://en.wikipedia.org/wiki/Binary_search_algorithm). – iRon Jun 19 '18 at 18:15
  • $hashFilesAndSizes.GetEnumerator() is not a hashtable and can be sorted. – Mikhail Tumashenko Jun 20 '18 at 10:29

3 Answers3

3

This

$hashSorted = $hashFilesAndSizes.GetEnumerator() | sort value 

does not produce a new hashtable. Instead, it produces an array of DictionaryEntry objects. Now since $hashSorted is, in fact, not a hashtable, there is no Keys property and indexing by value won't work. To properly construct a new hashtable that preserves key order you have to do

$hashSorted = [ordered] @{}
$hashFilesAndSizes.GetEnumerator() | sort value | foreach {$hashSorted[$_.Key] = $_.Value}
Bruce Payette
  • 2,511
  • 10
  • 8
1

Try to run in new clear powershell context. I suggest your environment has some variables saved in cache.

The only error I see is in the second loop. You're using $hashSorted inside the loop instead of $item. Should be:

  $key = $item.Key 
  ....
  $fileSize = $item.Value

EDIT: Btw, sorting with GetEnumerator() works just fine.

EDIT 2: $hashSorted.Keys is empty as $hashSorted is not a hashtable, just a collection of key-value pairs.

Mikhail Tumashenko
  • 1,683
  • 2
  • 21
  • 28
  • See: https://stackoverflow.com/questions/4656289/sort-hashtable-and-assign-it-to-a-new-variable-in-powershell - I'm still getting issues with nulls. Yes, some variables are not getting cleared, and I don't understand why. I init the hashtable at the top of my script. Fixed the typo, but still null issues. – NealWalters Jun 19 '18 at 15:02
  • Okay, same typo twice. I guess using GetNumerator works, but looping through keys doesn't. Saw another post that seemed to indicate that. – NealWalters Jun 19 '18 at 15:04
  • I run your script in fresh powershell instance and got expected result - no nulls at all. – Mikhail Tumashenko Jun 19 '18 at 15:07
0
Write-Host "Test with enumerator"

  foreach($item in $hashSorted.GetEnumerator()) 
   {
      $key = $item.Key                                        # Not $hashSorted.Key !
      Write-Host "Key=$key" 
      #if (-not ([string]::IsNullOrEmpty($key)))
      #{
          $keyPadded = $key.PadRight(50," ")
          $fileSize = $item.Value                             # Not $hashSorted.Value !
          $fileSizeFormatted = $fileSize.ToString("000,000")
          Write-Host "$keyPadded  size=$fileSizeFormatted "
      #}
   }
iRon
  • 20,463
  • 10
  • 53
  • 79