Sorting a 2D array with one row

2020-05-06 13:06发布

问题:

I've recently started scripting in PowerShell and I'm having a difficulty in sorting a 2D array by multiple columns.

The following code is working fine. I have a 2D array (5x4) and I sort it by two columns; first, by the second column, and then by the first column.

$table1 = ("hhctrl.ocx",21,503,"Microsoft® HTML Help Control"),("mscomct2.ocx",10,629,"Microsoft Common Controls 2 ActiveX Control DLL"),("msscript.ocx",2,86,"Microsoft ® Script Control"),("sysmon.ocx",15,384,"System Monitor Control"),("tdc.ocx",1,61,"TDC ActiveX Control")
$table1_sorted = $table1 | Sort-Object @{Expression={$_[1]}; Ascending=$false}, @{Expression={$_[0]}; Ascending=$true}

echo (var_dump $table1)
echo (var_dump $table1_sorted)

var_dump is a custom function. I've created it to debug arrays. Write-Host and echo, they both flatten the arrays and don't seperate the items (no comma between items) e.g.

hhctrl.ocx 21 503 Microsoft® HTML Help Control mscomct2.ocx 10 629 Microsoft Common Controls 2 ActiveX Control DLL msscript.ocx 2 86 Microsoft ® Script Control sysmon.ocx 15 384 System Monitor Control tdc.ocx 1 61 TDC ActiveX Control

var_dump outputs:

[
    [
        "hhctrl.ocx",
        21,
        503,
        "Microsoft® HTML Help Control"
    ],
    [
        "mscomct2.ocx",
        10,
        629,
        "Microsoft Common Controls 2 ActiveX Control DLL"
    ],
    [
        "msscript.ocx",
        2,
        86,
        "Microsoft ® Script Control"
    ],
    [
        "sysmon.ocx",
        15,
        384,
        "System Monitor Control"
    ],
    [
        "tdc.ocx",
        1,
        61,
        "TDC ActiveX Control"
    ]
]
[
    [
        "hhctrl.ocx",
        21,
        503,
        "Microsoft® HTML Help Control"
    ],
    [
        "sysmon.ocx",
        15,
        384,
        "System Monitor Control"
    ],
    [
        "mscomct2.ocx",
        10,
        629,
        "Microsoft Common Controls 2 ActiveX Control DLL"
    ],
    [
        "msscript.ocx",
        2,
        86,
        "Microsoft ® Script Control"
    ],
    [
        "tdc.ocx",
        1,
        61,
        "TDC ActiveX Control"
    ]
]

Now, if I use another array, "table" with only one row, sorting flattens the array.

$table2 = ,("hhctrl.ocx",21,503,"Microsoft® HTML Help Control")
$table2_sorted = $table2 | Sort-Object @{Expression={$_[1]}; Ascending=$false}, @{Expression={$_[0]}; Ascending=$true}

echo (var_dump $table2)
echo (var_dump $table2_sorted)

Output:

[
    [
        "hhctrl.ocx",
        21,
        503,
        "Microsoft® HTML Help Control"
    ]
]
[
    "hhctrl.ocx",
    21,
    503,
    "Microsoft® HTML Help Control"
]

This happens when there's only one row. Why is that?

回答1:

Sort-Object does not return array. It return write to pipeline individual input items in sorted order.

PS> 7,3,8,5,1 | Sort-Object | ForEach-Object { Write-Host "Item: $_" }
Item: 1
Item: 3
Item: 5
Item: 7
Item: 8

As you can see, next command in pipeline ForEach-Object see each individual item, but not array as whole.

Wrapping to array in $table1 case happens, because last command in pipeline wrote more than one item in pipeline. In $table2 case last command in pipeline wrote only one item, so no wrapping necessary there. If you want to always wrap pipeline results into array regardless of amount of results (zero, one or many), then you need to use array subexpression operator:

$Results = @( First-Command | Middle-Command | Last-Command )