哈希表和键顺序

Posted

技术标签:

【中文标题】哈希表和键顺序【英文标题】:Hashtables and key order 【发布时间】:2013-01-31 05:05:32 【问题描述】:

有没有办法在添加键时保持哈希表中键的顺序?就像推送/弹出机制一样。

例子:

$hashtable = @

$hashtable.Add("Switzerland", "Bern")
$hashtable.Add("Spain", "Madrid")
$hashtable.Add("Italy", "Rome")
$hashtable.Add("Germany", "Berlin")
$hashtable

我想保留将元素添加到哈希表的顺序。

【问题讨论】:

【参考方案1】:

您可以改用有序字典:

像这样:

$list = New-Object System.Collections.Specialized.OrderedDictionary
$list.Add("Switzerland", "Bern")
$list.Add("Spain", "Madrid")
$list.Add("Italy", "Rome")
$list.Add("Germany", "Berlin")
$list

【讨论】:

【参考方案2】:

PowerShell V1 / V2 中没有内置解决方案。您将需要使用 .NET System.Collections.Specialized.OrderedDictionary:

$order = New-Object System.Collections.Specialized.OrderedDictionary
$order.Add("Switzerland", "Bern")
$order.Add("Spain", "Madrid")
$order.Add("Italy", "Rome")
$order.Add("Germany", "Berlin")


PS> $order

Name                           Value
----                           -----
Switzerland                    Bern
Spain                          Madrid
Italy                          Rome
Germany                        Berlin

在 PowerShell V3 中,您可以强制转换为 [ordered]:

PS> [ordered]@"Switzerland"="Bern"; "Spain"="Madrid"; "Italy"="Rome"; "Germany"="Berlin"

Name                           Value
----                           -----
Switzerland                    Bern
Spain                          Madrid
Italy                          Rome
Germany                        Berlin

【讨论】:

感谢您的回答!我知道 PS v3 [已订购] 但我必须使用 PS 2.0 谢谢,说什么:奇怪的实现,我认为没有理由将该实现作为默认实现。你需要它来获得原始速度吗?为此做一个自定义类,并像大多数人所期望的那样,按照插入顺序对基进行排序。 请注意,如果要使用pass your ordered hash to a function,还必须使用此类型(System.Collections.Specialized.OrderedDictionary)作为参数。您不能使用 [ordered][hash] 快捷方式的风格作为参数类型,而必须使用完整类型。您可以作为[hash] 参数传递,但您会丢失排序(因为它作为不太具体的扩展hash 类型传递;更多在that link),这可能是不可取的。 ?【参考方案3】:

PowerShell 1 的方式是添加一个哈希表成员来保留添加顺序。无需使用 System.Collections.Specialized.OrderedDictionary:

$Hash = New-Object PSObject                                       
$Hash | Add-Member -MemberType NoteProperty -Name key1 -Value val1
$Hash | Add-Member -MemberType NoteProperty -Name key2 -Value val2
$Hash | Add-Member -MemberType NoteProperty -Name key3 -Value val3

【讨论】:

但这不是一个哈希表,它是一个 PSCustomObject。不是一回事,即使您将变量命名为“$Hash”。 ;) OrderedDictionary 的功能就像我尝试过的所有实际用途的哈希表一样。【参考方案4】:

为了与旧 PowerShell 版本兼容,您可以考虑使用此 cmdlet:

Function Order-Keys 
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)][HashTable]$HashTable,
        [Parameter(Mandatory = $false, Position = 1)][ScriptBlock]$Function,
        [Switch]$Descending
    )
    $Keys = $HashTable.Keys | ForEach $_ # Copy HashTable + KeyCollection
    For ($i = 0; $i -lt $Keys.Count - 1; $i++) 
        For ($j = $i + 1; $j -lt $Keys.Count; $j++) 
            $a = $Keys[$i]
            $b = $Keys[$j]
            If ($Function -is "ScriptBlock") 
                $a = $HashTable[$a] | ForEach $Function
                $b = $HashTable[$b] | ForEach $Function
            
            If ($Descending) 
                $Swap = $a -lt $b
            
            Else
            
                $Swap = $a -gt $b
            
            If ($Swap) 
                $Keys[$i], $Keys[$j] = $Keys[$j], $Keys[$i]
            
        
    
    Return $Keys

此 cmdlet 返回按函数定义排序的键列表:

按名称排序:

$HashTable | Order-Keys | ForEach Write-Host $_ $HashTable[$_]
Germany Berlin
Italy Rome
Spain Madrid
Switzerland Bern

按值排序:

$HashTable | Order-Keys $_ | ForEach Write-Host $_ $HashTable[$_]
Germany Berlin
Switzerland Bern
Spain Madrid
Italy Rome

您也可以考虑嵌套哈希表:

$HashTable = @
    Switzerland = @Order = 1; Capital = "Berne"
    Germany     = @Order = 2; Capital = "Berlin"
    Spain       = @Order = 3; Capital = "Madrid"
    Italy       = @Order = 4; Capital = "Rome"

例如按(散列)顺序属性排序并返回键(国家):

$HashTable | Order-Keys $_.Order | ForEach $_

或按预定义的大写排序(降序):

$HashTable | Order-Keys $_.Capital -Descending | ForEach $_

【讨论】:

【参考方案5】:

您可以在添加元素时提供一个顺序键:

$hashtable = @
$hashtable[$hashtable.count] = @("Switzerland", "Bern")
$hashtable[$hashtable.count] = @("Spain", "Madrid")
$hashtable[$hashtable.count] = @("Italy", "Rome")
$hashtable[$hashtable.count] = @("Germany", "Berlin")
$hashtable

然后,你可以得到按键排序的元素:

echo "`nHashtable keeping the order as they were added"
foreach($item in $hashtable.getEnumerator() | Sort Key)

    $item

【讨论】:

【参考方案6】:
function global:sortDictionaryByKey([hashtable]$dictionary)

    return $dictionary.GetEnumerator() | sort -Property name;

【讨论】:

欢迎来到 Stack Overflow。虽然这段代码可能会回答这个问题,但提供有关此代码为何和/或如何回答问题的附加上下文会提高其长期价值。How to Answer。谢谢!【参考方案7】:

这是一个适合我的简单例程。

function sortedKeys([hashtable]$ht) 
  $out = @()
  foreach($k in $ht.keys) 
    $out += $k
  
  [Array]::sort($out)
  return ,$out

以及使用它的调用

forEach($k in (& sortedKeys $ht)) 
  ...

【讨论】:

但问题是关于保持添加哈希的顺序,而不是按键排序。这如何回答这个问题? 彼得,你是对的。我很困惑,认为 Ordered 字典就像 Java TreeMap 而不是 LinkedHashMap。感谢您的澄清。

以上是关于哈希表和键顺序的主要内容,如果未能解决你的问题,请参考以下文章

数据结构与算法之数组链表和哈希表的Java实现

Java基础Map

三问了解哈希表和哈希冲突

大白话之哈希表和哈希算法

初级--03---二分复杂度哈希表和有序表

什么是哈希表和哈希映射以及它们的典型用例?