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
2条答案
按热度按时间8oomwypt1#
让我用更广阔的视角补充Maximilian Burszley's helpful answer:
tl;dr
****大多数情况下 * 您需要
[ordered] @{ ... }
**([System.Collections.Specialized.OrderedDictionary]
)(PSv 3+):.Keys
和.Values
集合属性中)。[ordered] @{ ... }
与常规哈希表@{ ... }
([hashtable]
,也称为[System.Collections.Hashtable]
)互换使用,因为这两种类型都实现了[IDictionary]
interface,这是接受哈希表的参数的典型类型。使用
[ordered]
所带来的性能损失可以忽略不计。一些背景:
出于 * 技术 * 原因,最有效 * 的哈希表(哈希表)实现是让条目的排序成为 * 实现细节 * 的结果,* 而不向调用者保证任何特定的顺序 。*
这对于您所做的只是按键执行隔离查找的用例是很好的,其中键(条目)之间的顺序是无关紧要的。
但是,您通常会关心条目的顺序:
**不幸的是,PowerShell的hashtable-literal语法
@{ ... }
并不 * 默认为 *[ordered]
[1],但现在改变已经太晚了。有一个上下文中
[ordered]
* 是 * 隐含的,然而:如果您将hashtable literal 转换为[pscustomobject]
以创建自定义对象:[pscustomobject] @{ ... }
是[pscustomobject] [ordered] @{ ... }
的 * 语法糖;也就是说,所得到的自定义对象的属性是基于哈希表文字中的条目顺序来排序的;例如:但是,请注意,此仅完全按照上面所示的方式工作:如果强制转换 * 直接 * 应用于哈希表 * 文字*;如果你使用一个 * 变量 * 来存储哈希表,或者你甚至只是将文字包含在
(...)
中,那么顺序就会丢失:因此,如果你先 * 迭代地 * 构造一个哈希表,然后 * 将其转换为
[pscustomobject]
,你必须从[ordered]
哈希表开始以获得可预测的属性顺序;这种技术很有用,因为创建哈希表条目比向自定义对象添加属性更容易;例如:最后,注意
[ordered]
只能应用于hashtable literal;你不能用它来将一个已经存在的常规哈希表转换成有序哈希表(这没有任何意义,因为你没有定义开始的顺序):顺便说一句:有序哈希表和常规哈希表在通过管道发送时都不会枚举它们的条目;它们被作为一个整体发送。
枚举条目时,使用
.GetEnumerator()
方法;例如:关于使用
[ordered]
的性能影响:如前所述,它是可忽略的;以下是使用
Time-Command
计算的10,000次运行的平均采样时间:示例计时(Windows 10上的Windows PowerShell 5.1,单核VM):
也就是说,
[ordered]
的增长速度仅下降了5%。[1]马克西米利安Burszley指出了
[ordered]
哈希表的一个棘手的方面:使用*数字 * 键,区分 * 键 * 和 * 索引 * 可能会变得棘手;要强制将数字解释为 * 键 *,请将其转换为
[object]
或使用 * 点表示法 *(.
,属性访问语法)而不是 * 索引语法 *([...]
):也就是说,数字键并不常见,对我来说,默认为可预测枚举的好处超过了这个小问题。
.NET类型的基础
[ordered]
,System.Collections.Specialized.OrderedDictionary
,从v1开始就可用,所以PowerShell可以从一开始就选择它作为@{ ... }
的默认实现,即使在PowerShell v1中也是如此。考虑到PowerShell对向后兼容性的承诺,更改默认值不再是一种选择,因为这可能会破坏现有代码,即以以下方式:
-is [hashtable]
的哈希表,这将不再适用于有序哈希表(但是,使用-is [System.Collections.IDictionary]
* 检查将 * 工作)。amrnrhlw2#
使用
ordered
字典的原因是为了显示/类型转换的目的。例如,如果你想将hashtable
转换为PSCustomObject
,并且你想让你的键按照你输入它们的顺序,你可以使用ordered
。这里的用例是,当你使用
Export-Csv
时,头的顺序是正确的。这只是我能想到的一个例子。通过设计,hashtable
类型不关心你输入键/值的顺序,每次你将它显示到成功流时都会不同。ordered
字典的另一个用例:你可以把你的哈希表当作一个数组,并使用数字访问器来查找项目,比如$myOrderedHash[-1]
将抓取添加到字典中的最后一个项目。