关于排序:在哈希表数组上使用Sort-Object

Using Sort-Object on array of hash tables

在PowerShell(版本2)中创建以下哈希表数组后:

1
2
3
4
5
$array = @()
$array += @{a = 1; b = 5}
$array += @{a = 3; b = 4}
$array += @{a = 5; b = 9}
$array += @{a = 7; b = 2}

排序对象的所有以下调用都返回相同的a,b序列:5,9,7,2,1,5,3,4:

1
2
3
4
5
6
7
8
$array | Sort-Object
$array | Sort-Object -Descending
$array | Sort-Object a
$array | Sort-Object b
$array | Sort-Object"a"
$array | Sort-Object -Property a
$array.GetEnumerator() | Sort-Object
$array.GetEnumerator() | Sort-Object a

如果直接调用$array,它将按输入对象的顺序返回对象,因此排序正在更改顺序。但也许它没有比较器,所以只是把每一个对象视为平等的??

目标是对所有对象进行排序。我可以使用涉及备用自定义对象、备用集合和/或备用排序例程的解决方法。

编辑:为了阐明我正在努力实现的目标,这在C语言中大致相当。#

1
2
3
4
5
6
7
8
9
class MyClass {
    public int a;
    public int b;
}

// somewhere inside a method:
var objects = new List<MyClass>();
// code here to populate objects with some MyClass instances.
var sorted = objects.OrderBy(x => x.a);


Sort-Object a不起作用,因为a不是属性,它是哈希表中的键。有人可能会困惑,因为PowerShell通过接受$ht.a,为您隐藏了这一点,即使它实际上在幕后使用$ht["a"],但如果运行$array | Get-Member,您可以确认属性a不存在。

解决方法是使用访问哈希表中键的计算属性进行排序。我使用Select-Object在表中显示哈希表,这样更容易看到结果。前任:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$array = @()
$array += @{a = 7; b = 2}
$array += @{a = 3; b = 4}
$array += @{a = 3; b = 1}
$array += @{a = 5; b = 9}
$array += @{a = 1; b = 5}

#No sort
$array | Select-Object @{n="a";e={$_.a}}, @{n="b";e={$_.b}}

a b
- -
7 2
3 4
3 1
5 9
1 5

#Sort by a asc, then b asc
$array | Sort-Object { $_.a },  { $_.b } | Select-Object @{n="a";e={$_.a}}, @{n="b";e={$_.b}}

a b
- -
1 5
3 1
3 4
5 9
7 2


有关详细解释,请参阅@frode f.的答案,但该答案确实遗漏了一种情况。当外部容器只有一个项(即数组只包含一个哈希表)时,排序对象"方便"地对内部容器排序。

所以…在$array.Count -eq 1中,对该哈希表的元素进行排序。其中$array.Count -gt 1对数组元素进行排序。

作为解决方法,使用:

1
2
3
4
5
if ($array.Count -gt 1) {
    $result = Sort-Object { $_.a }, {$_.b }
} else {
    $result = $array
}