通过专注于通过键值数组过滤哈希表(PSv3+ 语法)来补充briantist's helpful answer:
# Sample hashtable.
$ht = @{ one = 1; two = 2; three = 3 }
# Filter it by an array of key values; applying .GetEnumerator() yields an array
# of [System.Collections.DictionaryEntry] instances, which have
# a .Key property and a .Value property.
$ht.GetEnumerator() | ? Key -in 'one', 'two'
# Similarly, the *output* - even though it *looks* like a hashtable -
# is a regular PS *array* ([Object[]]) containing [System.Collections.DictionaryEntry]
# entries (2 in this case).
$arrFilteredEntries = $ht.GetEnumerator() | ? Key -in 'one', 'two'
$arrFilteredEntries.GetType().Name # -> Object[]
要进一步处理匹配的键值对,只需管道到% (ForEach-Object) 并访问$_.Key 和$_.Value(值):
$ht.GetEnumerator() | ? Key -in 'one', 'two' |
% { "Value for key '$($_.Key)': $($_.Value)" }
等效命令使用更高效的foreach循环代替管道:
foreach ($key in $ht.Keys) {
if ($key -in 'one', 'two') { "Value for key '$($key)': $($ht.$key)" }
}
注意:在 PSv2 中:
* 不支持运算符-in,但您可以使用-contains 来代替操作数交换:
'one', 'two' -contains $key
* 在管道中,使用Where-Object { 'one', 'two' -contains $_.Key }
使用示例哈希表,这会产生:
Value for key 'two': 2
Value for key 'one': 1
注意输出中的键顺序与定义顺序有何不同;在 PSv3+ 中,您可以创建 ordered 哈希表 ([ordered] @{ ... }) 以保留定义顺序。
上面使用的键过滤技术不仅限于通过文字键数组进行过滤;任何(字符串)集合都将作为 -in 操作数的 RHS,例如 不同 哈希表的 .Keys 集合:
# Sample input hashtable.
$htInput = @{ one = 1; two = 2; three = 3 }
# Hashtable by whose keys the input hashtable should be filtered.
# Note that the entries' *values* are irrelevant here.
$htFilterKeys = @{ one = $null; two = $null }
# Perform filtering.
$htInput.GetEnumerator() | ? Key -in $htFilterKeys.Keys |
% { "Value for key '$($_.Key)': $($_.Value)" }
# `foreach` loop equivalent:
foreach ($key in $htInput.Keys) {
if ($key -in $htFilterKeys.Keys) { "Value for key '$($key)': $($htInput.$key)" }
}
结果与静态过滤键数组的示例相同。
最后,如果您想过滤一个哈希表就地或创建一个新只包含过滤条目的哈希表强>:
# *In-place* Updating of the hashtable.
# Remove entries other than the ones matching the specified keys.
# Note: The @(...) around $ht.Keys is needed to clone the keys collection before
# enumeration, so that you don't get an error about modifying a collection
# while it is being enumerated.
foreach ($key in @($ht.Keys)) {
if ($key -notin 'one', 'two') { $ht.Remove($key) }
}
# Create a *new* hashtable with only the filtered entries.
# By accessing the original's .Keys collection, the need for @(...) is obviated.
$htNew = $ht.Clone()
foreach ($key in $ht.Keys) {
if ($key -notin 'one', 'two') { $htNew.Remove($key) }
}
顺便说一句:
[System.Collections.DictionaryEntry] 的默认输出格式(因此哈希表 ([System.Collections.Hashtable]) 使用列名 Name 而不是 Key;Name 被定义为 @ 的 别名属性 987654346@ 由 PowerShell 添加(它不是 [System.Collections.DictionaryEntry].NET type definition 的一部分;请使用
@{ one = 1 }.GetEnumerator() | Get-Member 验证)。