4

I have a list of items in a generic list:

  • A1 (sort index 1)
  • A2 (sort index 2)
  • B1 (sort index 3)
  • B2 (sort index 3)
  • B3 (sort index 3)

The comparator on them takes the form:

this.sortIndex.CompareTo(other.sortIndex)

When I do a List.Sort() on the list of items, I get the following order out:

  • A1
  • A2
  • B3
  • B2
  • B1

It has obviously worked in the sense that the sort indexes are in the right order, but I really don't want it to be re-ordering the 'B' items.

Is there any tweak I can make to my comparator to fix this?

Fiona - myaccessible.website
  • 14,481
  • 16
  • 82
  • 117
  • possible duplicate of [Why does List.Sort method reorder equal IComparable elements?](http://stackoverflow.com/questions/800007/why-does-listt-sort-method-reorder-equal-icomparablet-elements) – nawfal Jun 13 '14 at 12:02

5 Answers5

5

you need to use a "stable sort" algorithm if you don't want items that are equal to change position.

Check out "merge sort" for an example of a stable sort algorithm. Here's an implementation of it in C#.

Mark Heath
  • 48,273
  • 29
  • 137
  • 194
5

OrderBy preserves order for equal items:

myList = myList.OrderBy(item => item.SortIndex).ToList();
David Hedlund
  • 128,221
  • 31
  • 203
  • 222
2

StableSort() extension method for List<T> is here

Community
  • 1
  • 1
xhafan
  • 2,140
  • 1
  • 26
  • 26
1

You can change your comparator to do a secondary sort on the value:

if (this.sortIndex.CompareTo(other.sortIndex) == 0) // same sortIndex
{
   return this.Value.CompareTo(other.Value);
}
return 0;
Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • Is that not doing exactly the same thing as the example I posted? – Fiona - myaccessible.website Apr 20 '10 at 10:35
  • @Fiona: No, the code uses the value in a secondary comparison, but you have to do some corrections if you want to use it, as it messes up the primary comparison by returning zero instead of the result. – Guffa Apr 20 '10 at 10:42
  • Ah I see. I don't have a secondary comparison to use really (although I could add an artifical one and this would work fine), the list order I want to preserve is based on the output of a pretty complex recursive function. – Fiona - myaccessible.website Apr 20 '10 at 10:58
1

Sort uses QuickSort, and it doesn't assure original sequence in case of comparison equality.

If you still want to use List.Sort you could add a second comparison with the original index like:

int c = this.sortIndex.CompareTo(other.sortIndex);
if (c == 0)
  c = this.originalIndex.CompareTo(other.originalIndex);
return c;

otherwise you can sort with other "stable" algorithms (e.g. LINQ OrderBy).

digEmAll
  • 56,430
  • 9
  • 115
  • 140