如何通过一组键值枚举哈希表作为键值对/过滤哈希表

use*_*867 22 powershell hashtable

编者注: 这个问题有一个复杂的历史,但归结为:
*要了解如何通过其键值对枚举哈希表的条目,请参阅接受的答案.
*要了解如何通过一组键值过滤哈希表,请参阅另一个答案.


我想我再次遇到了XY问题,我最初的问题是关于过滤哈希表.我发现在创建哈希表之前过滤更容易.问题回答了,对吗?

不,Y问题是循环每个Key并使用@briantist帮助我的值.

我的目标是循环使用键名称(时间戳),并使用键名作为任务名称和触发器来安排任务.

我正在使用Group-Object -AsHashTable -AsString -editPipeline从CSV文件创建哈希表,这里值得一提的是,在创建HashTable之前过滤CSV只会使脚本更容易.

举个例子:

Import-CSV (ls -path D:\ -Filter source*.csv | sort LastWriteTime | Select -Last 1).FullName |
 where {$_.TimeCorrected -ne 'ManualRebootServer'} |
 group TimeCorrected -AsHashTable -AsString
Run Code Online (Sandbox Code Playgroud)

我正在尝试遍历键名并能够使用以下方法显示键名:

$var = Import-Csv csv123.csv | Group-Object Value1 -AsHashTable -AsString

foreach ($key in $var.Keys){"The key name is $key"}

#Create a scheduled task named and triggered based on the HashTable keyname
#test test test
foreach ($key in $var.keys){IF($key -ne 'ManualRebootServer'){"Register-ScheduledJob"}}
Run Code Online (Sandbox Code Playgroud)

我只是不确定如何从我感兴趣的键中获取值.

我发现以下工作,但只有当我手动输入密钥名称时.我只是不确定如何组合两个循环.

($val.GetEnumerator() | Where {$_.key -eq '06-11-16 18:00'} | ForEach-Object { $_.value }).Server
Run Code Online (Sandbox Code Playgroud)

bri*_*ist 39

你有一些选择.

枚举通过键:

foreach ($key in $var.Keys) {
    $value = $var[$key]
    # or
    $value = $var.$key 
}
Run Code Online (Sandbox Code Playgroud)

枚举键值对(您已发现,但可能无法有效使用):

foreach ($kvp in $var.GetEnumerator()) {
    $key = $kvp.Key
    $val = $kvp.Value
}
Run Code Online (Sandbox Code Playgroud)


mkl*_*nt0 9

通过关注通过键值数组(PSv3 +语法)过滤哈希表来补充briantist的有用答案:

# 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[]
Run Code Online (Sandbox Code Playgroud)

要进一步处理匹配的键值对,只需管道到%(ForEach-Object)并访问$_.Key$_.Value(值):

$ht.GetEnumerator()  | ? Key -in 'one', 'two' | 
  % { "Value for key '$($_.Key)': $($_.Value)" }
Run Code Online (Sandbox Code Playgroud)

使用更有效的foreach 循环而不是管道的等效命令:

foreach ($key in $ht.Keys) { 
  if ($key -in 'one', 'two') { "Value for key '$($key)': $($ht.$key)" }
}
Run Code Online (Sandbox Code Playgroud)

注意:在PSv2:
*运算符-in不受支持,但您可以使用-contains操作数swapled:
'one', 'two' -contains $key
*在管道中,使用Where-Object { 'one', 'two' -contains $_.Key }

使用示例哈希表,这会产生:

Value for key 'two': 2
Value for key 'one': 1
Run Code Online (Sandbox Code Playgroud)

请注意输出中的键顺序与定义顺序的不同之处; 在PSv3 +中,您可以创建有序的 hashtables([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)" }
}
Run Code Online (Sandbox Code Playgroud)

结果与使用静态filter-keys数组的示例相同.

最后,如果要在适当位置过滤哈希表创建仅包含已过滤条目的哈希表:

# *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) }
} 
Run Code Online (Sandbox Code Playgroud)

作为旁白:

为默认的输出格式[System.Collections.DictionaryEntry](因此哈希表([System.Collections.Hashtable])使用列名Name而非Key; Name被定义为别名属性Key由加入的PowerShell(它不是的一部分[System.Collections.DictionaryEntry].NET类型定义 ;与验证
@{ one = 1 }.GetEnumerator() | Get-Member).