我正在阅读教程并了解到PowerShell支持有序哈希.我什么时候会使用该功能?
我正在谈论的样本:
$hash = [ordered]@{ ID = 1; Shape = "Square"; Color = "Blue"}
Run Code Online (Sandbox Code Playgroud)
ordered字典的原因是用于显示/类型转换目的.例如,如果您想要将您的密钥转换hashtable为a,PSCustomObject并且您希望密钥符合您输入的顺序,则可以使用ordered.
这里的用例是当你使用时Export-Csv,标题的顺序是正确的.这只是我能想到的一个例子.按照设计,hashtable类型不关心输入键/值的顺序,每次将其显示到成功流时都会有所不同.
ordered字典的另一个用例:您可以将哈希表视为数组并使用数字访问器来查找项目,例如$myOrderedHash[-1]将获取添加到字典中的最后一项.
让我以更广阔的视角补充TheIncorrigible1的有用答案:
TL;博士
大多数时候你想要[ordered] @{ ... }([System.Collections.Specialized.OrderedDictionary])(PSv3 +):
.Keys和.Values集合属性中).通常情况下,你可以使用[ordered] @{ ... }互换@{ ... },定期哈希表,[hashtable]又名[System.Collections.Hashtable],因为这两种类型实现[IDictionary]的接口,这是多么接受哈希表参数一般类型.
您支付使用的性能损失可以[ordered]忽略不计.
一些背景:
由于技术原因,哈希表(哈希表)的最有效实现是让条目的排序成为实现细节的结果,而不保证对调用者的任何特定顺序.
这适用于所有操作都是按键执行隔离查找的用例,其中键(条目)之间的顺序无关紧要.
但是,通常您会关注条目的排序:
在最简单的情况下,用于显示目的; 看到定义顺序混乱,有些令人不安; 例如:
@{ one = 1; two = 2; three = 3 }
Name Value
---- -----
one 1
three 3 # !!
two 2
Run Code Online (Sandbox Code Playgroud)更重要的是,可能需要对条目的列举进行进一步的程序化处理; 例如(注意:严格来说,属性顺序在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
}
Run Code Online (Sandbox Code Playgroud)不幸的是,PowerShell的hashtable-literal语法@{ ... }并没有默认为 [ordered][1],但改变它已经太晚了.
有一个上下文中[ordered] 的暗示,但是:如果你投一个哈希表字面来[pscustomobject],以创建自定义对象:
[pscustomobject] @{ ... }是语法糖为[pscustomobject] [ordered] @{ ... } ; 也就是说,生成的自定义对象的属性是根据哈希表文本中的条目顺序排序的; 例如:
PS> [pscustomobject] @{ one = 1; two = 2; three = 3 }
one two three # order preserved!
--- --- -----
1 2 3
Run Code Online (Sandbox Code Playgroud)
但请注意,这仅与上面所示完全相同:如果转换直接应用于散列表文字 ; 如果您首先使用变量来存储哈希表,或者如果您只是将(...)序列中的文字括起来,则会丢失:
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
Run Code Online (Sandbox Code Playgroud)
因此,如果首先迭代地构造哈希表然后将其转换为哈希表,则[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
Run Code Online (Sandbox Code Playgroud)
最后,请注意,[ordered]只能应用于哈希表文字 ; 您不能使用它将预先存在的常规哈希表转换为有序哈希表(无论如何都没有任何意义,因为您没有定义的顺序开始):
PS> $ht = @{ one = 1; two = 2; three = 3 }; [ordered] $ht # !! Error
...
The ordered attribute can be specified only on a hash literal node.
...
Run Code Online (Sandbox Code Playgroud)
旁注:当通过管道发送时,有序或常规哈希表都不会枚举它们的条目 ; 它们是作为一个整体发送的.
要枚举条目,请使用该.GetEnumerator()方法 ; 例如:
@{ one = 1; two = 2; three = 3 }.GetEnumerator() | ForEach-Object { $_.Value }
1
3 # !!
2
Run Code Online (Sandbox Code Playgroud)
至于使用的性能影响[ordered]:
如上所述,它可以忽略不计 ; 以下是一些样本计时,平均10,000次运行,使用Time-Command:
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} }
Run Code Online (Sandbox Code Playgroud)
示例计时(Windows 10上的Windows PowerShell 5.1,单核VM):
Command TimeSpan Factor
------- -------- ------
$ht=@{one=1;two=2;th... 00:00:00.0000501 1.00
$ht=[ordered] @{one=... 00:00:00.0000527 1.05
Run Code Online (Sandbox Code Playgroud)
也就是说,[ordered]仅减速仅为5%.
[1] TheIncorrigible1指出了一个特定于[ordered]哈希表的棘手方面:
使用数字键,区分键和索引可能会变得棘手; 强制将数字解释为键,将其强制转换为[object]:
# 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
Run Code Online (Sandbox Code Playgroud)
也就是说,数字键并不常见,对我来说,默认可预测枚举的好处超过了这个小问题.
.NET框架类型底层[ordered], System.Collections.Specialized.OrderedDictionary自v1以来就已经可用,因此@{ ... }即使在PowerShell v1中,PowerShell也可以从一开始就选择它作为默认实现.
鉴于PowerShell对向后兼容性的承诺,更改默认值不再是一种选择,因为这可能会破坏现有代码.
| 归档时间: |
|
| 查看次数: |
662 次 |
| 最近记录: |