Powershell 排序哈希 table

Powershell sorting hash table

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

这在 class

之外工作正常
$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

我看到哈希的内容两次,未排序然后排序。 但是,当使用 class 时它什么都不做。

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()

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

$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)!!"
}

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

$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

现在的输出是

conformset 3!
applyset 1!

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

applyset                       1                                                                                                                                                                              
conformset                     3  

显然 $hash 正在排序。但是循环不会显示它?嗯?这是有问题的行为,还是我只是不明白原因的预期行为,因此如何解决?

当您执行 $hash = $hash.GetEnumerator() | Sort-Object -property:Value 时,您正在将哈希表重新分配给数组,请尝试 $hash.GetType() ,这当然与哈希表的行为不同,您可以查看方法等等 Get-Member -InputObject $hash

我认为您不能对哈希表进行排序,也不需要。您可以试试 Ordered Dictionary $hash = [Ordered]@{}

Ordered dictionaries differ from hash tables in that the keys always appear in the order in which you list them. The order of keys in a hash table is not determined.

我喜欢的哈希表的最佳用途之一是搜索速度。 例如,您可以通过以下方式立即获取哈希表中某个名称的值 $hash['applyset']

如果您想了解更多哈希表的工作原理,并how/when使用它,我认为这篇文章是一个很好的开始: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_hash_tables?view=powershell-6

  • 解释了您方法的根本问题:

    • 从根本上说,您不能按键对散列 table[hashtable] 实例)进行排序:散列中键的顺序table不保证,不可更改。

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

  • 一个不相关的问题是您通常不能隐式从 PowerShell classes[=70] 写入输出流=]:

    • 从 class 方法写入输出流需要显式使用 return;同样,必须通过 Throw 语句报告错误。
    • 在你的例子中,代码在 构造函数 中用于 class Test,并且构造函数隐式 return 新构造的实例 -你不能 return 从他们那里得到任何东西。

要解决您的问题,您需要一种专门的数据类型,它结合了散列table 的特征,并以排序顺序 维护输入键].[1]

.NET 类型 System.Collections.SortedList provides this functionality (there's also a generic version, as 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++

甚至从现有哈希转换(和转换为)table:

# 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

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