powershellpowershell-corepowershell-7

Hash key and value do not compare equally


Why is an integer hash key not an integer? The key is of type KeyCollection even though it was created from a constant integer.

The script to produce this output is below. I will show only the last three (3) command lines. Why is the key not some type of integer?

PS C:\> $h.Keys[0].GetType()    # the type of the first and only item in the set of keys is KeyCollection, not an int of some kind

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
False    False    KeyCollection                            System.Object

PS C:\> 1 -eq $h.Keys[0]        # comparing 1 and the key both ways produces different results ???
False
PS C:\> $h.Keys[0] -eq 1
1

PS C:\> $PSVersionTable.PSVersion.ToString()
7.3.6

Here is the script that led to this.

$h = @{}
$hi1 = @{1='a';2='b'}   # create a hash
$h.GetType()            # yes, it is a hashtable
$h.Count                # there should be none (0) at this point
$h[1] += @($hi1)        # put an array containing a hash into h
$h[1]                   # check to see that the array containing a hash is in the hash h
$h[1].Count             # there should be one (1) item in the hash
$h[1].GetType()         # the item at hash index 1 should be an array
$h[1][0]                # this is the first and only element in the array
$h[1][0].GetType()      # the first item in the array is a hashtable

$h.Keys                 # there is only one key in the hash
$h.Keys.GetType()       # the type of the Keys object is a KeyCollection
$h.Keys[0]              # the first and only item in the set of keys is 1
$h.Keys[0].GetType()    # the type of the first and only item in the set of keys is KeyCollection, not an int of some kind
1 -eq $h.Keys[0]        # comparing 1 and the key both ways produces different results ???
$h.Keys[0] -eq 1

Solution

  • It looks like this question might have already been answered here

    In case that isn't helpful,

    It is my understanding that the KeyCollection object returned by the Keys property isn't indexed (nor does it have a built in iterator). So when you try to index into the object with indice 0 PowerShell is just returning the whole object. If you were to try and access indice 1 for instance, you would get nothing back.

    You should be able to cast the Keys object to an array by doing something similar to [Array]$keys_arr = $h.Keys. You could then access the indices on this array to your hearts content (just be aware that the order of the keys appears to be backwards? I assume that key order is probably undefined in this instance)

    Alternatively, if you just needed to access a specific index, you could do ([Array]$h.Keys)[0] -eq ...

    In addition to the SO post linked above, you can also read a bit more about KeyCollections in this Reddit post.

    As for why you are getting different results when flipping the equality statement, this comment by Jeroen Mostert on another answer seems to do a decent job explaining the non-symmetrical nature of -eq in PWSH:

    Equality in PowerShell is not a symmetrical operation. Per the docs: "When the input is a collection of values, the comparison operators return any matching values. If there are no matches in a collection, comparison operators do not return anything." So $null -eq $abc tests if $abc is $null itself, $abc -eq $null finds the $null values in $abc -- and prints nothing, since that's what $null looks like when output. (Compare $abc -eq 7.)

    Hope this helps!