我正在阅读教程,并了解到PowerShell支持有序哈希。我什么时候使用该功能?
我正在谈论的示例:
$hash = [ordered]@{ ID = 1; Shape = "Square"; Color = "Blue"}
答案 0 :(得分:9)
使用insert
词典的原因是出于显示/打字的目的。例如,如果您要将ordered
强制转换为PSCustomObject
,并且希望您的键按输入顺序排列,请使用hashtable
。
这里的用例是当您使用Export-Csv
时,标题顺序正确。这只是我想到的一个例子。根据设计,ordered
类型与输入键/值的顺序无关,每次显示到成功流中时,顺序都会有所不同。
hashtable
字典的另一个用例:您可以将哈希表视为数组,并使用数字访问器查找项目,例如ordered
将抢占添加到字典中的最后一个项目。
答案 1 :(得分:6)
让我以更广阔的视角补充TheIncorrigible1's helpful answer:
tl; dr
大部分时间[ordered] @{ ... }
([System.Collections.Specialized.OrderedDictionary]
)(PSv3 +):
.Keys
和.Values
集合属性中)。通常,您可以将[ordered] @{ ... }
与常规哈希表@{ ... }
又称为[System.Collections.Hashtable]
[hashtable]
互换使用,因为这两种类型都实现了[IDictionary]
interface ,通常是输入哈希表参数的方式。
您使用[ordered]
支付的性能损失可以忽略不计。
一些背景:
出于技术原因,哈希表(哈希表)的最有效实现是让条目的顺序成为实现的结果详细信息,不保证向呼叫者的特定订单。
这对于用例来说,您要做的就是按键执行孤立的查找,而键(条目)之间的顺序无关紧要。
但是,您经常会关心条目的顺序:
在最简单的情况下,出于 display 的目的;看到定义顺序混乱,有些令人不安;例如:
@{ one = 1; two = 2; three = 3 }
Name Value
---- -----
one 1
three 3 # !!
two 2
更重要的是,可能需要对条目的枚举进行预测以进行进一步的程序处理;例如(注意:严格来说,属性顺序在JSON中无关紧要,但对人类观察者来说同样重要):
# No guaranteed property order.
PS> @{ one = 1; two = 2; three = 3 } | ConvertTo-Json
{
"one": 1,
"three": 3, # !!
"two": 2
}
# Guaranteed property order.
PS> [ordered] @{ one = 1; two = 2; three = 3 } | ConvertTo-Json
{
"one": 1,
"two": 2,
"three": 3
}
很遗憾,PowerShell的哈希表文字语法@{ ... }
不是默认为 [ordered]
[1] ,但是改变这一点为时已晚。
在一种情况下,其中隐含[ordered]
,但是:如果将哈希表 literal 强制转换为{{1 }}来创建自定义对象:
[pscustomobject]
是[pscustomobject] @{ ... }
的语法糖;也就是说,根据哈希表文字中的输入顺序对生成的自定义对象的属性进行排序;例如:
[pscustomobject] [ordered] @{ ... }
但是,请注意,此仅与上述完全相同:如果强制转换直接将 应用于哈希表 literal ;如果您先使用变量将哈希表存储在其中,或者什至只将文字括在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]
最后,请注意$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
只能应用于哈希表 literal ;您不能使用它将预先存在的常规哈希表转换为有序哈希表(无论如何,这毫无用处,因为您没有定义的开头):
[ordered]
附带说明:有序哈希表和常规哈希表在通过管道发送时都不会枚举其条目;它们作为整体发送。
要枚举条目,请使用PS> $ht = @{ one = 1; two = 2; three = 3 }; [ordered] $ht # !! Error
...
The ordered attribute can be specified only on a hash literal node.
...
方法;例如:
.GetEnumerator()
关于使用@{ one = 1; two = 2; three = 3 }.GetEnumerator() | ForEach-Object { $_.Value }
1
3 # !!
2
对性能的影响:
如前所述,它可以忽略;以下是一些使用Time-Command
的示例计时,平均运行10,000次:
[ordered]
示例计时(Windows 10上的Windows PowerShell 5.1,单核VM):
Time-Command -Count 10,000 { $ht=@{one=1;two=2;three=3;four=4;five=5;six=6;seven=7;eight=8;nine=9}; foreach($k in $ht.Keys){$ht.$k} },
{ $ht=[ordered] @{one=1;two=2;three=3;four=4;five=5;six=6;seven=7;eight=8;nine=9}; foreach($k in $ht.Keys){$ht.$k} }
也就是说,Command TimeSpan Factor
------- -------- ------
$ht=@{one=1;two=2;th... 00:00:00.0000501 1.00
$ht=[ordered] @{one=... 00:00:00.0000527 1.05
仅降低了5%。
[1] TheIncorrigible1指出了一个专门针对[ordered]
哈希表的精巧方面:
使用 数字键,区分键和索引会变得很棘手; 要强制将数字解释为键,请将其强制转换为[ordered]
:
[object]
也就是说,数字键并不常见,对我来说,默认使用可预测的枚举的好处要胜过这个小问题。
自v1以来,基于# 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框架类型已经可用,因此PowerShell可以从一开始就选择它作为System.Collections.Specialized.OrderedDictionary
的默认实现,甚至在PowerShell v1中。
鉴于PowerShell致力于向后兼容,但是更改默认值不再是一个选择,因为那样可能会破坏现有代码。