Home > database >  C# in-place sort on elements that have a defined property
C# in-place sort on elements that have a defined property

Time:04-15

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

  • Related