Powershell 排序哈希表

Gor*_*don 2 sorting powershell hashtable

我在排序的哈希表中看到一些看似非常奇怪的行为,然后尝试查看结果。我构建了哈希表,然后我需要根据值对该表进行排序,我看到了两个奇怪的地方。

这在课堂外工作正常

$hash = [hashtable]::New()
$type = 'conformset'
$hash.Add($type, 1)
$type = 'applyset'
$hash.Add($type , 1)
$type = 'conformset'
$hash.$type ++
$hash.$type ++
$hash
Write-Host
$hash = $hash.GetEnumerator() | Sort-Object -property:Value
$hash
Run Code Online (Sandbox Code Playgroud)

我看到散列的内容两次,未排序然后排序。然而,当使用一个类时它什么也不做。

class Test {
    # Constructor (abstract class)
    Test () {
        $hash = [hashtable]::New()
        $type = 'conformset'
        $hash.Add($type, 1)
        $type = 'applyset'
        $hash.Add($type , 1)
        $type = 'conformset'
        $hash.$type ++
        $hash.$type ++
        $hash
        Write-Host
        $hash = $hash.GetEnumerator() | Sort-Object -property:Value
        $hash
    }
}

[Test]::New()
Run Code Online (Sandbox Code Playgroud)

这只是将 Test 回显到控制台,与哈希表无关。我的假设是,它与管道如何中断有关,老实说,考虑到管道错误的常见污染程度,这是转移到类的一个很好的理由。因此,转向基于循环的方法,这无法显示类中的第二个已排序、已排序的哈希表。

$hash = [hashtable]::New()
$type = 'conformset'
$hash.Add($type, 1)
$type = 'applyset'
$hash.Add($type , 1)
$type = 'conformset'
$hash.$type ++
$hash.$type ++

foreach ($key in $hash.Keys) {
    Write-Host "$key $($hash.$key)!"
}
Write-Host
$hash = ($hash.GetEnumerator() | Sort-Object -property:Value)
foreach ($key in $hash.Keys) {
    Write-Host "$key $($hash.$key)!!"
}
Run Code Online (Sandbox Code Playgroud)

但是,非常奇怪的是,这仅显示了第一个基于循环的输出,但同时显示了直接转储。

$hash = [hashtable]::New()
$type = 'conformset'
$hash.Add($type, 1)
$type = 'applyset'
$hash.Add($type , 1)
$type = 'conformset'
$hash.$type ++
$hash.$type ++

foreach ($key in $hash.Keys) {
    Write-Host "$key $($hash.$key)!"
}
$hash
Write-Host
$hash = ($hash.GetEnumerator() | Sort-Object -property:Value)
foreach ($key in $hash.Keys) {
    Write-Host "$key $($hash.$key)!!"
}
$hash
Run Code Online (Sandbox Code Playgroud)

现在的输出是

conformset 3!
applyset 1!

Name                           Value                                                                                                                                                                          
----                           -----                                                                                                                                                                          
conformset                     3                                                                                                                                                                              
applyset                       1                                                                                                                                                                              

applyset                       1                                                                                                                                                                              
conformset                     3  
Run Code Online (Sandbox Code Playgroud)

所以显然 $hash 正在被排序。但是循环不会显示它?嗯?这是错误的行为,还是我不明白其原因的预期行为,以及解决方法?

mkl*_*nt0 6

  • Vasil Svilenov Nikolov 的有用回答解释了您的方法的基本问题:

    • 从根本上讲,您无法[hashtable]按键对哈希表(实例)进行排序:哈希表中键的顺序无法保证且无法更改。

    • 什么$hash = $hash.GetEnumerator() | Sort-Object -property:Value所做的是不是创建一个数组[System.Collections.DictionaryEntry]实例; 结果数组没有.Keys属性,因此foreach ($key in $hash.Keys)永远不会进入您的第二个循环。

  • 一个不相关的问题是您通常无法从 PowerShell隐式写入输出流:

    • 从类方法写入输出流需要显式使用return; 同样,错误必须通过Throw语句报告。
    • 在您的情况下,代码位于class的构造函数Test,并且构造函数隐式返回新构造的实例 - 您不允许return从它们中获得任何东西。

为了解决您的问题,您需要一种专门的数据类型,它将哈希表的功能与按排序顺序维护条目键相结合[1]

.NET 类型System.Collections.SortedList提供了这个功能(还有一个通用版本,正如Lee Dailey所说):

您可以使用该类型开始:

# Create a SortedList instance, which will maintain
# the keys in sorted order, as entries are being added.
$sortedHash = [System.Collections.SortedList]::new()

$type = 'conformset'
$sortedHash.Add($type, 1) # Or: $sortedHash[$type] = 1 or: $sortedHash.$type = 1
$type = 'applyset'
$sortedHash.Add($type , 1)
$type = 'conformset'
$sortedHash.$type++
$sortedHash.$type++
Run Code Online (Sandbox Code Playgroud)

或者甚至从(和到)现有的哈希表转换:

# Construct the hash table as before...
$hash = [hashtable]::new() # Or: $hash = @{}
$type = 'conformset'
$hash.Add($type, 1)
$type = 'applyset'
$hash.Add($type , 1)
$type = 'conformset'
$hash.$type++
$hash.$type++

# ... and then convert it to a SortedList instance with sorted keys.
$hash = [System.Collections.SortedList] $hash
Run Code Online (Sandbox Code Playgroud)

[1] 请注意,这与 PowerShell 使用文字语法提供的有序字典不同[ordered] @{ ... }:有序字典按照键的插入顺序维护键,而不是基于排序。有序字典的类型System.Collections.Specialized.OrderedDictionary