Let's imagine I have a list, all elements have an order property except for Element with Id 4:
List<Element> elements = new List<Element> {
new Element {Id = 1, Name = "First", Order = 2},
new Element {Id = 2, Name = "Second", Order = 3},
new Element {Id = 3, Name = "Third", Order = 1},
new Element {Id = 4, Name = "Fourth", Order = null};
I need to sort elements in-place based on the order property but the element with Id 4 is not taken into consideration as it has order property set to null.
public void ModifyList() {
Order(elements);
return elements; // I want to end up with Element Id:3,
// Element Id:1, Element Id:2 and the last
// one Element with Id:4 (it is returned
// as the last element as the sort did not apply to it.
}
private static void Order(IList<Element> elements) {
elements.Sort((x, y) => x.Order.CompareTo(y.Order));
}
I know that I could first create one list that contains elements that have order property, sort them, and than append to the list which does not have that property, is there a cleaner way to do it. (without using OrderBy()).
CodePudding user response:
You can write your own comparer to ensure that the Nulls go at the end:
public sealed class ElementComparer: IComparer<Element>
{
public int Compare(Element? x, Element? y)
{
if (ReferenceEquals(x, y))
return 0;
if (ReferenceEquals(null, y))
return 1;
if (ReferenceEquals(null, x))
return -1;
if (x.Order == null)
return 1;
if (y.Order == null)
return -1;
return x.Order.Value.CompareTo(y.Order.Value);
}
}
Then you can in-place sort the elements in the list like so:
elements.Sort(new ElementComparer());
If you try it, you'll see that it's ordered by .Order
but with any null ones at the end.
One thing to be aware of is that List<T>.Sort()
is an unstable sort, which means that after sorting, the order of items with the same .Order
(including null ones) is undefined.
Enumerable.OrderBy()
performs a stable sort.
CodePudding user response:
Try:
foreach(var item in elements.OrderBy( x=> (x.Order is null ? 9999 : x.Order))) {
System.Console.WriteLine(item.Id);
}
Of course you should change the 9999
when the values of Id
are also in that range...
see: fiddle