Search code examples
sortingpowershellstable-sort

Does Powershell Sort-Object use a stable sort


I need to create a distinct list of history items from multiple sources, where the most recent item is the one kept. I'm trying something like this but because of the problem domain it is not simple to check that the result is accurate.

Function GetUnique {
    param( $source1, $source2, ...)

    $items = $source1 + $source2 + ...;

    $unique = $items | Sort-Object -Desc -Unique -Prop Timestamp;

    # Does this contain the most recent items?

    $unique;
}

I'm reasonably surprised there is no -Stable switch to indicate the preference.

Note: I'm aware that even if the sort is stable, I'm making an assumption about the uniqueness algorithm. If the sort is stable, I can write my own stable Get-Unique commandlet relatively easily that assumes stable sorted input. However, I don't really want to implement MergeSort.


Solution

  • So after throwing away my scenario, I found a simple test to show that the sort is not actually stable but somehow reverses the sequence in a stable manner. Note, the test set I'm using is pretty small so these results could be inconclusive but are reproducible.

    function f ([String] $name, [int] $value) `
    {
        return New-Object PSObject -Property @{ Name=$name; Value=$value } | 
            select Name,Value; 
    };
    $test = (f a 1),(f a 2),(f a 3),(f b 1),(f b 2);
    "`n`$test;"
    $test;
    "`n`$test | sort name;"
    $test | sort name;
    "`n`$test | sort name -Desc;"
    $test | sort name -Desc;
    "`n`$test | sort name | sort name;"
    $test | sort name | sort name;
    "`n`$test | sort value | sort name;"
    $test | sort value | sort name;
    "`n`$test | sort value;"
    $test | sort value;
    

    The results are as follow:

    $test;
    Name                                                  Value
    ----                                                  -----
    a                                                         1
    a                                                         2
    a                                                         3
    b                                                         1
    b                                                         2
    
    $test | sort name;
    a                                                         3
    a                                                         2
    a                                                         1
    b                                                         2
    b                                                         1
    
    $test | sort name -Desc;
    b                                                         1
    b                                                         2
    a                                                         1
    a                                                         2
    a                                                         3
    
    $test | sort name | sort name;
    a                                                         1
    a                                                         2
    a                                                         3
    b                                                         1
    b                                                         2
    
    $test | sort value | sort name;
    a                                                         2
    a                                                         1
    a                                                         3
    b                                                         1
    b                                                         2
    
    $test | sort value;
    b                                                         1
    a                                                         1
    b                                                         2
    a                                                         2
    a                                                         3
    

    I've submitted a suggestion to the PS team regarding this at https://connect.microsoft.com/PowerShell/feedback/details/752455/provide-stable-switch-for-sort-object-cmdlet. Please upvote if you agree.