为什么要在PowerShell中使用有序哈希?
我正在阅读教程,了解到PowerShell支持有序散列。我什么时候可以使用该功能 我所说的示例代码:为什么要在PowerShell中使用有序哈希?,powershell,Powershell,我正在阅读教程,了解到PowerShell支持有序散列。我什么时候可以使用该功能 我所说的示例代码: $hash = [ordered]@{ ID = 1; Shape = "Square"; Color = "Blue"} 订购字典的原因是为了显示/打字。例如,如果您想将哈希表强制转换为a,并且希望密钥按输入顺序排列,则可以使用ordered 这里的用例是当您使用时,标题的顺序是正确的。这只是我脑海中能想到的一个例子。根据设计,hashtable类型与您输入键/值的顺序无关,每次将其显示到成
$hash = [ordered]@{ ID = 1; Shape = "Square"; Color = "Blue"}
订购
字典的原因是为了显示/打字。例如,如果您想将哈希表
强制转换为a,并且希望密钥按输入顺序排列,则可以使用ordered
这里的用例是当您使用时,标题的顺序是正确的。这只是我脑海中能想到的一个例子。根据设计,hashtable
类型与您输入键/值的顺序无关,每次将其显示到成功流时都会有所不同
有序
字典的另一个用例是:您可以将哈希表视为数组,并使用数字访问器查找项,例如$myOrderedHash[-1]
将获取添加到字典中的最后一项。让我从更广阔的角度补充一下:
tl;dr
- 大多数情况下,您需要
[ordered]@{…}
()(PSv3+):
- 它按条目的定义顺序提供条目的枚举(也反映在
.Keys
和.Values
集合属性中)
- 它还允许通过索引访问条目,如数组
- 通常,您可以将
[ordered]@{…}
与常规哈希表@{…}
互换使用,即[hashtable]
a.k.a,因为这两种类型都实现了,这是接受哈希表的参数的典型类型
您因使用[ordered]
而支付的性能罚款可以忽略不计
一些背景:
出于技术原因,哈希表(哈希表)的最有效实现是让条目的顺序成为实现细节的结果,而不保证调用方的任何特定顺序。
对于只需按键执行独立查找的用例来说,这很好,因为键(条目)之间的顺序是不相关的
但是,您通常关心条目的顺序:
- 在最简单的情况下,用于显示目的;看到定义顺序混乱令人不安;e、 g:
@{ one = 1; two = 2; three = 3 }
Name Value
---- -----
one 1
three 3 # !!
two 2
- 更重要的是,条目的枚举可能需要可预测,以便进行进一步的编程处理;e、 g.(注意:严格来说,属性顺序在JSON中并不重要,但对人类观察者来说同样重要):
不幸的是,PowerShell的哈希表文本语法,@{…}
,没有默认为[ordered]
[1],但现在更改已经太晚了。
有一个上下文隐含了[ordered]
,但是:如果为了创建自定义对象而将哈希表文本强制转换为[pscustomobject]
:
[pscustomobject]@{…}
是[pscustomobject][ordered]@{…}
的语法糖;也就是说,结果自定义对象的属性是基于哈希表文本中的条目顺序排序的;e、 g:
PS> [pscustomobject] @{ one = 1; two = 2; three = 3 }
one two three # order preserved!
--- --- -----
1 2 3
但是,请注意,仅能像上面所示那样工作:如果强制转换直接应用于哈希表文本;如果首先使用变量存储哈希表,或者仅将文本括在(…)
中,则顺序将丢失:
PS> $ht = @{ one = 1; two = 2; three = 3 }; [pscustomobject] $ht
one three two # !! Order not preserved.
--- ----- ---
1 3 2
PS> [pscustomobject] (@{ one = 1; two = 2; three = 3 }) # Note the (...)
one three two # !! Order not preserved.
--- ----- ---
1 3 2
因此,如果先迭代构造哈希表,然后将其强制转换为[pscustomobject]
,则必须从[ordered]
哈希表开始,以获得可预测的属性顺序;这种技术很有用,因为创建哈希表条目比向自定义对象添加属性更容易;e、 g:
$oht = [ordered] @{} # Start with an empty *ordered* hashtable
# Add entries iteratively.
$i = 0
foreach ($name in 'one', 'two', 'three') {
$oht[$name] = ++$i
}
[pscustomobject] $oht # Convert the ordered hashtable to a custom object
最后,请注意,[ordered]
只能应用于哈希表文本;您不能使用它将先前存在的常规哈希表转换为有序哈希表(无论如何,这没有任何意义,因为您没有定义的开始顺序):
另一方面:当通过管道发送时,有序哈希表和常规哈希表都不会枚举它们的条目;它们作为一个整体发送。
要枚举条目,使用.GetEnumerator()
方法;e、 g:
@{ one = 1; two = 2; three = 3 }.GetEnumerator() | ForEach-Object { $_.Value }
1
3 # !!
2
关于使用[订购]
对性能的影响:
# Ordered hashtable with numeric keys.
PS> $oht = [ordered] @{ 1 = 'one'; 2 = 'two' }
PS> $oht[1] # same as $oht.1 - interpreted as *index* -> 2nd entry
two
PS> $oht[[object] 1] # interpreted as *key* -> 1st entry.
one
如前所述,它可以忽略不计;以下是一些示例计时,平均10000次运行,使用:
计时示例(Windows 10上的Windows PowerShell 5.1,单核VM):
也就是说,[ordered]
只造成了5%的减速
[1] InCorrigible1指出了特定于哈希表的一个棘手方面:
# Ordered hashtable with numeric keys.
PS> $oht = [ordered] @{ 1 = 'one'; 2 = 'two' }
PS> $oht[1] # same as $oht.1 - interpreted as *index* -> 2nd entry
two
PS> $oht[[object] 1] # interpreted as *key* -> 1st entry.
one
使用数字键,区分键和索引可能会变得棘手要强制将数字解释为键,请将其强制转换为[对象]
:
# Ordered hashtable with numeric keys.
PS> $oht = [ordered] @{ 1 = 'one'; 2 = 'two' }
PS> $oht[1] # same as $oht.1 - interpreted as *index* -> 2nd entry
two
PS> $oht[[object] 1] # interpreted as *key* -> 1st entry.
one
也就是说,数字键并不常见,对我来说,默认使用可预测枚举的好处超过了这个小问题
[ordered]
基础的.NET framework类型,即System.Collections.Specialized.OrderedDictionary
,从v1开始就可以使用,因此PowerShell可以从一开始就选择它作为@{…}
的默认实现,即使在PowerShell v1中也是如此。
鉴于PowerShell对向后兼容性的承诺,更改默认值不再是一种选择,因为这可能会破坏现有代码。“不会默认为ordered,但现在更改已经太晚了。”为什么?也就是说,如果它被改变成那样(可能是在某个主要版本中),会有什么坏掉的呢?@hyde:虽然有些东西已经坏掉了,特别是
Command TimeSpan Factor
------- -------- ------
$ht=@{one=1;two=2;th... 00:00:00.0000501 1.00
$ht=[ordered] @{one=... 00:00:00.0000527 1.05
# Ordered hashtable with numeric keys.
PS> $oht = [ordered] @{ 1 = 'one'; 2 = 'two' }
PS> $oht[1] # same as $oht.1 - interpreted as *index* -> 2nd entry
two
PS> $oht[[object] 1] # interpreted as *key* -> 1st entry.
one