【问题标题】: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

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

【问题讨论】:

    标签: powershell sorting hashtable powershell-2.0


    【解决方案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。感谢您的澄清。
          猜你喜欢
          • 2014-12-30
          • 2021-09-29
          • 1970-01-01
          • 1970-01-01
          • 2011-12-09
          • 2010-10-25
          • 1970-01-01
          • 2022-01-19
          • 2017-03-17
          相关资源
          最近更新 更多