Mat*_*ald 3 powershell enumeration hashtable enumerator
这可能是一个愚蠢的问题,所以请友善,哈哈。我正试图集中精力思考我刚刚遇到的事情。
第一的
我有一个可以使用以下内容枚举的哈希表:
$ht = [hashtable]@{"Key1"="Value1";"Key2"="Value2"}
$ht.GetEnumerator()
Name Value
---- -----
Key1 Value1
Key2 Value2
Run Code Online (Sandbox Code Playgroud)
如果我将其存储到一个变量中,则它仅在该变量的一次调用中存在。
$KeyPairs = $ht.GetEnumerator()
$KeyPairs
Name Value
---- -----
Key1 Value1
Key2 Value2
$KeyPairs
# Nothing is returned as if $KeyPairs lost its value
Run Code Online (Sandbox Code Playgroud)
有人可以帮助我理解为什么会这样吗?
第二
通常,对于集合,我有时想要针对单个项目进行测试(例如查看一个实例的属性),我可以使用 Select-Object 或通过索引:
$array = @("Value1","Value2")
$array | select -first 1
Value1
$array[0]
Value1
Run Code Online (Sandbox Code Playgroud)
哈希表枚举器似乎只支持 Select-Option,而不支持索引。
$ht = [hashtable]@{"Key1"="Value1";"Key2"="Value2"}
$ht.GetEnumerator() | Select -first 1
$ht.GetEnumerator() | Select -first 1
Name Value
---- -----
Key1 Value1
($ht.GetEnumerator() | measure).count
2
($ht.GetEnumerator())[0]
Name Value
---- -----
Key1 Value1
Key2 Value2
Run Code Online (Sandbox Code Playgroud)
有人也可以解释一下吗?为什么我不能在这里使用索引选项?$ht.GetEnumerator() 返回一个 Dictionary 集合,当使用 Select -first 1 时,它返回单个 DictionaryEntry,但是当引用索引时,它返回两个字典条目。
注意:这个答案同样适用于 API直接返回枚举器对象的情况。
using.GetEnumerator()
返回键值对的枚举器[1] ,与枚举的结果不同。
.MoveNext()
要获得所需的行为,请通过数组子表达式运算符强制枚举@(...)
,并使用结果:
# Note the use of @(...), which collects the enumerated objects
# in an [object[]] array.
# Get an array of key-value pairs.
$KeyPairs = @($ht.GetEnumerator())
# Get the first key-value pair.
@($ht.GetEnumerator())[0]
Run Code Online (Sandbox Code Playgroud)
笔记:
在管道中, PowerShell 本身执行枚举器对象的枚举,这就是为什么类似的东西
$ht.GetEnumerator() | ForEach-Object { <# work with each key-value pair #> }
可以工作。
在管道中,哈希表/字典在技术上也是集合,与数组等类似列表的集合不同,默认情况下不会枚举它们。[2]也就是说,默认情况下,哈希表/字典作为一个整体通过管道发送,这就是为什么需要调用来返回其 条目(键值对)的枚举器,然后管道将枚举该枚举器。.GetEnumerator()
至于你尝试过的:
Run Code Online (Sandbox Code Playgroud)$KeyPairs # Nothing is returned as if $KeyPairs lost its value
因为$KeyPairs
包含一个enumerator,所以它是在隐式执行的输出到管道(显示)的第一个枚举之后完成枚举的,因此在重新调用时没有什么可枚举的- 除非您先调用。
但是,请注意,并非每个枚举器都保证支持重复枚举- 某些枚举器总是执行一次性枚举。$KeyPairs.Reset()
.Reset()
Run Code Online (Sandbox Code Playgroud)($ht.GetEnumerator())[0] # !! DOESN'T WORK
无法对枚举器建立索引。
PowerShell 将其视为单个对象(确实如此)并回退到其自己的索引,其中甚至允许对单个对象(标量)进行索引,以便统一处理集合和标量;在这种情况下,[0]
是一个有效的no-op,只需返回单个对象本身(类似于(42)[0]
和)(42)[-1]
42
[1] 具体来说,.GetEnumerator()
返回一个实现该System.Collections.IDictionaryEnumerator
接口的对象。
[2] 请参阅此答案的底部部分,了解 PowerShell 在管道中自动枚举哪些类型和不自动枚举哪些类型。
$KeyPairs
在你的例子中$KeyPairs = $ht.GetEnumerator()
是一个误导性的名称,你没有在该变量中分配键/值对,你拥有的是一个类型的对象,一个实现接口的HashtableEnumerator
类型,这个接口基本上是一个“合同”,指定如何哈希表可以而且应该被枚举。实现的细节之一是实例可以被枚举一次,如果你想再次枚举它,你必须调用它的方法。据我所知,这适用于实现接口的任何类型( 的基本接口)。IDictionaryEnumerator
.Reset()
IEnumerator
IDictionaryEnumerator
PS ..\pwsh> $ht = @{'Key1' = 'Value1'; 'Key2' = 'Value2' }
PS ..\pwsh> $enum = $ht.GetEnumerator()
PS ..\pwsh> $enum
Name Value
---- -----
Key1 Value1
Key2 Value2
PS ..\pwsh> $enum.Reset()
PS ..\pwsh> $enum
Name Value
---- -----
Key1 Value1
Key2 Value2
Run Code Online (Sandbox Code Playgroud)
至于第二个问题:
哈希表枚举器似乎只支持
Select-Option
,而不支持索引。
如果要使用索引,则必须将其转换为usingHashtableEnumerator
的集合,在这种情况下,首先使用哈希表就没有意义,它将失去其目的。DictionaryEntry
@($ht.GetEnumerator())
或者,更好的方法是使用OrderedDictionary
,这种类型支持按索引和按键访问,并且在执行查找时与普通哈希表一样快:
$dict = [ordered]@{'Key1' = 'Value1'; 'Key2' = 'Value2' }
$dict[0] # Value1
$dict.Keys[0] # Key1
# or, for a key / value pair:
[System.Collections.DictionaryEntry]::new($dict.Keys[0], $dict[0])
# Name Value
# ---- -----
# Key1 Value1
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
78 次 |
最近记录: |