如何从比较器未知的哈希表/字典中获取原始键?
获取哈希表/字典的原始键值
给定如下哈希表(或字典):
$HashTable = @{ 'One' = 1; 'Two' = 2; 'Three' = 3 }
该哈希表默认不区分大小写,但实际场景中使用的比较器未知。我们可以轻松通过以下方式获取指定项的对应值:
$HashTable['two'] # 或:$HashTable.get_item('two') 2
但能否通过类似如下方式获取指定项的实际原始键?
$HashTable.get_Key('two')
即返回带有大写字母T的Two,而非报错或小写的two?
更新1
为明确需求,重新表述问题:
对于任意给定、比较器未知的哈希表(或字典),希望能像获取值那样获取指定项的原始key,要求:
- 若键不存在,返回空(与通过该键查询值的行为一致)
- 若键存在,返回单个原始键(与获取单个值的行为一致)
我曾一度认为答案是:
无法实现
但keys集合中仍保留完整键,只是似乎丢失了与对应项的反向关联...
更新2
原本期望得到两种结果之一:标准的原始键获取方法,或“无法实现”及原因。但实际得到了多种可行替代方案,因实际场景对性能及符合预期性有要求,遂搭建Pester测试基准进行验证:
Describe '从哈希表或字典中检索原始键' { BeforeAll { $CaseInsensitive = [Ordered]@{ One = 1 Two = 2 Three = 3 4 = 'Four' } $CaseSensitive = [System.Collections.Specialized.OrderedDictionary]::new() $CaseSensitive['One'] = 1 $CaseSensitive['two'] = 2 $CaseSensitive['Two'] = 2 $CaseSensitive['three'] = 3 $CaseSensitive['Three'] = 3 $CaseSensitive['THREE'] = 3 $CaseSensitive[[Object]4] = 'Four' # mklement0 实现 function GetKey($Dictionary, $lookupKey) { if ($Dictionary.Contains($lookupKey)) { $candidateKeys = $Dictionary.Keys.Where({ $_ -eq $lookupKey }, 0, 2) if ($candidateKeys.Count -ge 2) { $lookupKey } else { $candidateKeys[0] } } } # Fabrice SANGA 实现(已注释) # $CaseInsensitive | Add-Member -Force -MemberType ScriptMethod -Name get_Key -Value { # param([string] $CaseInsensitiveIndex) # return $this.Keys.Where{ $_ -ceq ([CultureInfo]::InvariantCulture).TextInfo.ToTitleCase($CaseInsensitiveIndex) } # } # $CaseSensitive | Add-Member -Force -MemberType ScriptMethod -Name get_Key -Value { # param([string] $CaseInsensitiveIndex) # return $this.Keys.Where{ $_ -ceq ([CultureInfo]::InvariantCulture).TextInfo.ToTitleCase($CaseInsensitiveIndex) } # } # function GetKey($Dictionary, $lookupKey) { # $Dictionary.get_Key($lookupKey) # } # Abraham Zinala 实现(已注释) # function GetKey($HashTable, $to_match) { # [System.Linq.Enumerable]::Where( # ($entries = [System.Collections.DictionaryEntry[]]@($HashTable.GetEnumerator())), # [Func[System.Collections.DictionaryEntry, bool]]{ # param($entry) # $entry.Key -match $to_match -and $entries.Where{$_.Key -match $to_match}.Count -eq 1 -or # $entry.Key -cmatch $to_match -and $entries.Where{$_.Key -match $to_match}.Count -ge 1 # } # ).Key # } # iRon 实现(已注释) # function GetKey($Dictionary, $LookupKey) { # if ($Dictionary -is [System.Collections.IDictionary]) { # if (-not $Dictionary.Contains($LookupKey)) { return } # } else { # if (-not $Dictionary.ContainsKey($LookupKey)) { return } # } # foreach ($Key in $Dictionary.get_Keys()) { # if ($Key -ceq $LookupKey) { return $Key } # if ($Key -ieq $LookupKey) { $iKey = $Key } # } # if ($Null -ne $iKey) { $iKey } else { $LookupKey } # } } Context '不区分大小写,键存在的情况' { It 'One' { $CaseInsensitive['One'] | Should -Be 1 GetKey $CaseInsensitive 'One' | Should -BeExactly 'One' } It 'ONE' { $CaseInsensitive['ONE'] | Should -Be 1 GetKey $CaseInsensitive 'ONE' | Should -BeExactly 'One' } It 'two' { $CaseInsensitive['two'] | Should -Be 2 GetKey $CaseInsensitive 'two' | Should -BeExactly 'Two' } It 'Two' { $CaseInsensitive['Two'] | Should -Be 2 GetKey $CaseInsensitive 'Two' | Should -BeExactly 'Two' } It 'TWO' { $CaseInsensitive['TWO'] | Should -Be 2 GetKey $CaseInsensitive 'TWO' | Should -BeExactly 'Two' } It 'three' { $CaseInsensitive['three'] | Should -Be 3 GetKey $CaseInsensitive 'three' | Should -BeExactly 'Three' } It 'Three' { $CaseInsensitive['Three'] | Should -Be 3 GetKey $CaseInsensitive 'Three' | Should -BeExactly 'Three' } It 'THREE' { $CaseInsensitive['THREE'] | Should -Be 3 GetKey $CaseInsensitive 'THREE' | Should -BeExactly 'Three' } It '4' { $CaseInsensitive[[Object]4] | Should -Be 'Four' GetKey $CaseInsensitive 4 | Should -Be 4 } } Context '不区分大小写,键不存在的情况' { It '"4"' { $CaseInsensitive['4'] | Should -BeNullOrEmpty GetKey $CaseInsensitive '4' | Should -BeNullOrEmpty } } Context '区分大小写,键存在的情况' { It 'One' { $CaseSensitive['One'] | Should -Be 1 GetKey $CaseSensitive 'One' | Should -BeExactly 'One' } It 'two' { $CaseSensitive['Two'] | Should -Be 2 GetKey $CaseSensitive 'Two' | Should -BeExactly 'Two' } It 'Two' { $CaseSensitive['Two'] | Should -Be 2 GetKey $CaseSensitive 'Two' | Should -BeExactly 'Two' } It 'three' { $CaseSensitive['three'] | Should -Be 3 GetKey $CaseSensitive 'three' | Should -BeExactly 'three' } It 'Three' { $CaseSensitive['Three'] | Should -Be 3 GetKey $CaseSensitive 'Three' | Should -BeExactly 'Three' } It 'THREE' { $CaseSensitive['THREE'] | Should -Be 3 GetKey $CaseSensitive 'THREE' | Should -BeExactly 'THREE' } It '4' { $CaseInsensitive[[Object]4] | Should -Be 'Four' GetKey $CaseInsensitive 4 | Should -Be 4 } } Context '区分大小写,键不存在的情况' { It 'one' { $CaseSensitive['one'] | Should -BeNullOrEmpty GetKey $CaseSensitive 'one' | Should -BeNullOrEmpty } It 'ONE' { $CaseSensitive['ONE'] | Should -BeNullOrEmpty GetKey $CaseSensitive 'ONE' | Should -BeNullOrEmpty } It 'TWO' { $CaseSensitive['TWO'] | Should -BeNullOrEmpty GetKey $CaseSensitive 'TWO' | Should -BeNullOrEmpty } It 'Four' { $CaseSensitive['Four'] | Should -BeNullOrEmpty GetKey $CaseSensitive 'Four' | Should -BeNullOrEmpty } It '"4"' { $CaseInsensitive['4'] | Should -BeNullOrEmpty GetKey $CaseInsensitive '4' | Should -BeNullOrEmpty } } }
内容的提问来源于stack exchange,提问作者iRon
相关产品推荐
相关产品推荐

