Add -Stable
to Sort-Object
and related tests (#7862)
This commit is contained in:
parent
be4b82c730
commit
41d9667307
|
@ -16,8 +16,20 @@ namespace Microsoft.PowerShell.Commands
|
|||
public sealed class SortObjectCommand : OrderObjectBase
|
||||
{
|
||||
#region Command Line Switches
|
||||
|
||||
/// <summary>
|
||||
/// This param specifies if sort order is ascending.
|
||||
/// Gets or sets a value indicating whether a stable sort is required.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
/// <remarks>
|
||||
/// Items that are duplicates according to the sort algorithm will appear
|
||||
/// in the same relative order in a stable sort.
|
||||
/// </remarks>
|
||||
[Parameter(ParameterSetName = "Default")]
|
||||
public SwitchParameter Stable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the sort order is descending.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public SwitchParameter Descending
|
||||
|
@ -26,30 +38,25 @@ namespace Microsoft.PowerShell.Commands
|
|||
|
||||
set { DescendingOrder = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This param specifies if only unique objects are filtered.
|
||||
/// Gets or sets a value indicating whether the sort filters out any duplicate objects.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
[Parameter]
|
||||
public SwitchParameter Unique
|
||||
{
|
||||
get { return _unique; }
|
||||
public SwitchParameter Unique { get; set; }
|
||||
|
||||
set { _unique = value; }
|
||||
}
|
||||
|
||||
private bool _unique;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// This param specifies you only want the top N items returned.
|
||||
/// Gets or sets the number of items to return in a Top N sort.
|
||||
/// </summary>
|
||||
[Parameter(ParameterSetName = "Default")]
|
||||
[Parameter(ParameterSetName = "Top", Mandatory = true)]
|
||||
[ValidateRange(1, int.MaxValue)]
|
||||
public int Top { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// This param specifies you only want the bottom N items returned.
|
||||
/// Gets or sets the number of items to return in a Bottom N sort.
|
||||
/// </summary>
|
||||
[Parameter(ParameterSetName = "Bottom", Mandatory = true)]
|
||||
[ValidateRange(1, int.MaxValue)]
|
||||
|
@ -99,7 +106,7 @@ namespace Microsoft.PowerShell.Commands
|
|||
// versions of PowerShell).
|
||||
dataToSort.Sort(comparer);
|
||||
|
||||
if (_unique)
|
||||
if (Unique)
|
||||
{
|
||||
// Move unique entries to the front of the list (this is significantly faster
|
||||
// than removing them)
|
||||
|
@ -119,7 +126,8 @@ namespace Microsoft.PowerShell.Commands
|
|||
|
||||
// Identify how many items will be in the heap and the current number of items
|
||||
int heapCount = 0;
|
||||
int heapCapacity = Top > 0 ? Top : Bottom;
|
||||
int heapCapacity = Stable ? int.MaxValue
|
||||
: Top > 0 ? Top : Bottom;
|
||||
|
||||
// Identify the comparator (the value all comparisons will be made against based on whether we're
|
||||
// doing a Top N or Bottom N sort)
|
||||
|
@ -135,7 +143,7 @@ namespace Microsoft.PowerShell.Commands
|
|||
int comparator = Top > 0 ? -1 : 1;
|
||||
|
||||
// For unique sorts, use a sorted set to avoid adding unique items to the heap
|
||||
SortedSet<OrderByPropertyEntry> uniqueSet = _unique ? new SortedSet<OrderByPropertyEntry>(orderByPropertyComparer) : null;
|
||||
SortedSet<OrderByPropertyEntry> uniqueSet = Unique ? new SortedSet<OrderByPropertyEntry>(orderByPropertyComparer) : null;
|
||||
|
||||
// Tracking the index is necessary so that unsortable items can be output at the end, in the order
|
||||
// in which they were received.
|
||||
|
@ -149,7 +157,7 @@ namespace Microsoft.PowerShell.Commands
|
|||
}
|
||||
|
||||
// If we're doing a unique sort and the entry is not unique, discard the duplicate entry
|
||||
if (_unique && !uniqueSet.Add(dataToSort[dataIndex]))
|
||||
if (Unique && !uniqueSet.Add(dataToSort[dataIndex]))
|
||||
{
|
||||
discardedDuplicates++;
|
||||
if (dataIndex != dataToSort.Count - discardedDuplicates)
|
||||
|
@ -244,13 +252,14 @@ namespace Microsoft.PowerShell.Commands
|
|||
// Track the number of items that will be output from the data once it is sorted
|
||||
int sortedItemCount = dataToProcess.Count;
|
||||
|
||||
// If -Top & -Bottom were not used, or if -Top or -Bottom would return all objects, invoke
|
||||
// an in-place full sort
|
||||
if ((Top == 0 && Bottom == 0) || Top >= dataToProcess.Count || Bottom >= dataToProcess.Count)
|
||||
// If -Stable, -Top & -Bottom were not used, invoke an in-place full sort
|
||||
if (!Stable && Top == 0 && Bottom == 0)
|
||||
{
|
||||
sortedItemCount = FullSort(dataToProcess, comparer);
|
||||
}
|
||||
// Otherwise, use an indexed min-/max-heap to perform an in-place sort of all objects
|
||||
// Otherwise, use an indexed min-/max-heap to perform an in-place heap sort (heap
|
||||
// sorts are inheritantly stable, meaning they will preserve the respective order
|
||||
// of duplicate objects as they are sorted on the heap)
|
||||
else
|
||||
{
|
||||
sortedItemCount = Heapify(dataToProcess, comparer);
|
||||
|
|
|
@ -225,6 +225,80 @@ Describe "Sort-Object DRT Unit Tests" -Tags "CI" {
|
|||
}
|
||||
}
|
||||
|
||||
Describe 'Sort-Object Stable Unit Tests' -Tags 'CI' {
|
||||
|
||||
Context 'Modulo stable sort' {
|
||||
|
||||
$unsortedData = 1..20
|
||||
|
||||
It 'Return each value in an ordered set, sorted by the value modulo 3, with items having the same result appearing in the same order' {
|
||||
$results = $unsortedData | Sort-Object {$_ % 3} -Stable
|
||||
|
||||
$results[0] | Should -Be 3
|
||||
$results[1] | Should -Be 6
|
||||
$results[2] | Should -Be 9
|
||||
$results[3] | Should -Be 12
|
||||
$results[4] | Should -Be 15
|
||||
$results[5] | Should -Be 18
|
||||
$results[6] | Should -Be 1
|
||||
$results[7] | Should -Be 4
|
||||
$results[8] | Should -Be 7
|
||||
$results[9] | Should -Be 10
|
||||
$results[10] | Should -Be 13
|
||||
$results[11] | Should -Be 16
|
||||
$results[12] | Should -Be 19
|
||||
$results[13] | Should -Be 2
|
||||
$results[14] | Should -Be 5
|
||||
$results[15] | Should -Be 8
|
||||
$results[16] | Should -Be 11
|
||||
$results[17] | Should -Be 14
|
||||
$results[18] | Should -Be 17
|
||||
$results[19] | Should -Be 20
|
||||
}
|
||||
|
||||
It 'Return each value in an ordered set, sorted by the value modulo 3 (descending), with items having the same result appearing in the same order' {
|
||||
$results = $unsortedData | Sort-Object {$_ % 3} -Stable -Descending
|
||||
|
||||
$results[0] | Should -Be 2
|
||||
$results[1] | Should -Be 5
|
||||
$results[2] | Should -Be 8
|
||||
$results[3] | Should -Be 11
|
||||
$results[4] | Should -Be 14
|
||||
$results[5] | Should -Be 17
|
||||
$results[6] | Should -Be 20
|
||||
$results[7] | Should -Be 1
|
||||
$results[8] | Should -Be 4
|
||||
$results[9] | Should -Be 7
|
||||
$results[10] | Should -Be 10
|
||||
$results[11] | Should -Be 13
|
||||
$results[12] | Should -Be 16
|
||||
$results[13] | Should -Be 19
|
||||
$results[14] | Should -Be 3
|
||||
$results[15] | Should -Be 6
|
||||
$results[16] | Should -Be 9
|
||||
$results[17] | Should -Be 12
|
||||
$results[18] | Should -Be 15
|
||||
$results[19] | Should -Be 18
|
||||
}
|
||||
|
||||
It 'Return each value in an ordered set, sorted by the value modulo 3, discarding duplicates' {
|
||||
$results = $unsortedData | Sort-Object {$_ % 3} -Stable -Unique
|
||||
|
||||
$results[0] | Should -Be 3
|
||||
$results[1] | Should -Be 1
|
||||
$results[2] | Should -Be 2
|
||||
}
|
||||
|
||||
It 'Return each value in an ordered set, sorted by the value modulo 3 (descending), discarding duplicates' {
|
||||
$results = $unsortedData | Sort-Object {$_ % 3} -Stable -Unique -Descending
|
||||
|
||||
$results[0] | Should -Be 2
|
||||
$results[1] | Should -Be 1
|
||||
$results[2] | Should -Be 3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'Sort-Object Top and Bottom Unit Tests' -Tags 'CI' {
|
||||
|
||||
# Helper function to compare two sort entries
|
||||
|
|
Loading…
Reference in a new issue