在 powershell 中的有序字典中查找键的索引

finding index of key in an ordered dictionary in powershell

我在 powershell 中使用 hashtables/dictionaries 遇到了一些麻烦。最近的障碍是在有序字典中查找键索引的能力。

考虑以下示例:

$dictionary = [Ordered]@{
    'a' = 'blue';
    'b'='green';
    'c'='red'
    }

如果这是一个普通数组,我可以使用 IndexOf() 查找条目的索引。

[array]::IndexOf($dictionary,'c'). 

正常情况下会return2。

不过,如果我尝试使用有序字典,我会得到 -1。

有什么解决办法吗?


编辑: 万一有人读到这篇文章想知道我在说什么。我试图用它来创建一个对象,以一种也具有数字顺序的方式规范化 属性 条目。

我试图将其用于进程状态,例如:

$_processState = [Ordered]@{
     'error' = 'error'
     'none' = 'none'
     'started' = 'started'
     'paused' = 'paused'
     'cleanup' = 'cleanup'
     'complete' = 'complete'
}

如果您能够轻松做到这一点,上面的对象会给 $_processState.error 一个索引值 0 并通过每个条目递增,最后给 $_processState.complete 一个索引值 5。然后如果您通过 "index value" 比较了两个属性,您可以通过简单的运算符查看哪个属性更靠前。例如:

$thisObject.Status = $_processState.complete
If ($thisObject.Status -ge $_processState.cleanup) {Write-Host 'All done!'}

PS > All done!

^^这不能按原样工作,但就是这个想法。这就是我的目标。或者也许可以找到类似 $_processState.complete.IndexNumber()

的东西

拥有这样的对象还可以让您通过索引名称本身分配值,同时标准化选项...

$thisObject.Status = $_processState.paused
$thisObject.Status

PS > paused

不太确定这是当时最好的方法,或者它是否仍然是 PS v5.

中可用的所有自定义 class 选项的最佳方法

字典使用键而不是索引。 OrderedDictionary 结合了 hashtableArrayList 以在字典中为您提供 order/index-support,但它仍然是字典 (key-based) 集合。

如果您需要获取 OrderedDictionary(或 hasthable)中对象的索引,您需要使用 foreach-loop 和一个计数器。示例(应创建为函数):

$hashTable = [Ordered]@{
    'a' = 'blue';
    'b'='green';
    'c'='red'
}

$i = 0
foreach($key in $hashTable.Keys) {
    if($key -eq "c") { $i; break }
    else { $i++ }
}

这也是它在内部运作的方式。您可以通过阅读 .NET Reference Source

OrderedDictionaryIndexOfKey 方法的源代码来验证这一点

可以更简单

它可能不会比 Frode F. 的答案更有效,但可能更简洁(内联)只是将散列 table 的 keys 集合放在子表达式中($()) 然后对结果调用 indexOf。

对于你的散列table...

您的特定表达方式很简单:

$($dictionary.keys).indexOf('c')

...如您所料给出值 2。这在常规散列 table 上也同样适用……除非散列 table 几乎以任何方式被修改,当然……所以在那种情况下它可能不是很有用。

换句话说

使用这个散列table(它也展示了很多编码方式4...):

$hashtable = [ordered]@{
    sample = 'hash table'
    0 = 'hello'
    1 = 'goodbye'
    [char]'4' = 'the ansi character 4 (code 52)'
    [char]4 = 'the ansi character code 4'
    [int]4 = 'the integer 4'
    '4' = 'a string containing only the character 4'
    5 = "nothing of importance"
}

将产生以下 expression/results 对:

# Expression                                 Result
#-------------------------------------      -------------
$($hashtable.keys).indexof('5')              -1
$($hashtable.keys).indexof(5)                 7
$($hashtable.keys).indexof('4')               6
$($hashtable.keys).indexof([char]4)           4
$($hashtable.keys).indexof([int]4)            5
$($hashtable.keys).indexof([char]'4')         3
$($hashtable.keys).indexof([int][char]'4')   -1
$($hashtable.keys).indexof('sample')          0

顺便说一句:

  • [int][char]'4' 等于 [int]52
  • [char]'4' 的 "value"(量级?)为 52,但它是一个字符,所以它被用作

...非常喜欢打字系统,它虽然灵活,但如果您不小心,有时会变得非常糟糕。

对于我试图解决的最初问题,一个类似的进程状态,您现在可以使用从 PowerShell v5 开始的枚举。

您使用 Enum 关键字,按名称设置枚举器,并给它们一个整数值。该值可以是任何值,但在此示例中我使用的是从 0 开始的升序值:

Enum _ProcessState{
    Error = 0
    None = 1
    Started = 2
    Paused = 3
    Cleanup = 4
    Complete = 5
    Verified = 6
}

#the leading _ for the Enum is just cosmetic & not required

创建枚举后,您可以将其分配给变量。变量的内容将 return 枚举的文本名称,您可以将它们作为整数进行比较。

$Item1_State = [_ProcessState]::Started
$Item2_State = [_ProcessState]::Cleanup

#return state of second variable
$Item2_state

#comparison
$Item1_State -gt $Item2_State

将return:

Cleanup
False

如果你想和return最高的比较:

#sort the two objects, then return the first result (should return the item with the largest enum int)
$results = ($Item1_State,$Item2_State | Sort-Object -Descending)
$results[0]

有趣的是,您还可以对它们进行算术运算,例如:

$Item1_State + 1
$Item1_State + $Item2_State

将return:

Paused
Verified

此处枚举的更多信息: