I know I can add to an [Ordered] hash table at a particular index, with
$ordered.Insert([Int], [String], [String])
and I can set the value at a certain index with
$ordered[[Int]] =
And that leads me to THINK that I should also be able to GET the index of a given key. It seems that direct access isn't possible, as there in no .IndexOf()
method. But I know I can get an array of the keys, and an array does have .IndexOf()
, but that then returns another array, of -1
for the non matches and 0
for the matches.
So
$ordered = [Ordered]@{
'one' = 1
'two' = 2
'three' = 3
'four' = 4
}
$ordered
$ordered.Keys.IndexOf('two')
produces
Name Value
---- -----
one 1
two 2
three 3
four 4
-1
0
-1
-1
So now I need to get the index of that 0. So that doesn't seem to be the way to do it. I also found this. And indeed this works.
[Array]::IndexOf($ordered.Keys,'three')
But it has me wondering, is there a way to make the previous approach work? $ordered.Keys.IndexOf([String])
just seems like it should be viable, and I am just missing how to extract only the successful match. But perhaps not, and the static method is the way to go?
CodePudding user response:
In Windows PowerShell, use @(...)
to convert the .Keys
collection to a regular array, on which you can call .IndexOf()
:
@($ordered.Keys).IndexOf('two')
Note: Unlike direct, key-based access to your ordered hashtable, .IndexOf()
is case-sensitive.
As Santiago Squarzon points out, the use of @(...)
is no longer necessary in PowerShell (Core) 7.3 (.NET 7 ), where the collection type contained in the .Keys
property value itself implements the IList
interface and therefore directly supports .IndexOf()
.
Note:
The above also applies to accessing
.Keys
by index, e.g.@($ordered.Keys)[0]
/$ordered.Keys[0]
As of this writing, the 7.3 / .NET 7 improvement will only apply to
System.Collections.Specialized.OrderedDictionary
, the type that PowerShell's[ordered] @{ ... }
literal syntax creates instances of, and not also to other ordered or sorted dictionary types; GitHub issue #63537 aims to change that.
As for what happened in your attempt:
Since in Windows PowerShell the .Keys
collection itself has no .IndexOf()
method, member-access enumeration was performed, resulting in .IndexOf()
calls - as a string method - on each key.
CodePudding user response:
As an alternative to mklement0's helpful answer you could also extend the type itself adding a new PSScriptMethod
to find index of a Key. This can be accomplished with Update-TypeData
.
Update-TypeData -MemberType ScriptMethod -MemberName GetIndexOf -Value {
param([object] $Key)
return [array]::IndexOf($this.Keys, $Key)
} -TypeName System.Collections.Specialized.OrderedDictionary
$ordered.GetIndexOf('four') # => 3