Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

order list where top level order is unknown

Tags:

c#

sorting

linq

To order a list with Linq we have to call OrderBy first en call ThenBy on the result for subordinate orderings.

I'm in a situation now where I do not know the top level ordering before hand. I have a list of of orderings which should be applied conditionally.

Like this:

var list = new List<Tuple<int, string, DateTime>>();
list.Add(new Tuple<int, string, DateTime>(1, "B", new DateTime(2020, 1, 1)));
list.Add(new Tuple<int, string, DateTime>(2, "A", new DateTime(2000, 1, 1)));
list.Add(new Tuple<int, string, DateTime>(3, "C", new DateTime(1900, 1, 1)));

var orderedList = list;

if (sortByString)
{
    orderdedList = orderedList.ThenBy(listItem => listItem.Item2);
}

if (sortByDateTime)
{
    orderedList = orderedList.ThenBy(listItem => listItem.Item3);
}

orderList = orderedList.ThenBy(listItem => listItem.Item1);

So the list will always be ordered by Item1, and conditionally by Item2 and/or Item3 first.

How to accomplish this in C#? Solutions without Linq are also welcome.

like image 769
Johan van der Slikke Avatar asked Sep 07 '15 12:09

Johan van der Slikke


1 Answers

Just use

var orderedItems = list.OrderBy(_ => 1);

This gives you the default (non-)ordering, and allows you to add as many other orderings as you want afterwards using just ThenBy.

EDIT:

As Tim noted, this does carry a performance penalty - it seems that the default LINQ-to-Objects provider isn't smart enough to rebuild the ordering to get rid of the "non-ordering". This is not a problem if your list is small, but if it's taking non-negligible amount of time, you probably want to do this the hard way.

For example, you could use a helper method like

public static IEnumerable<T> AppendOrdering<T, U>(this IEnumerable<T> @this, 
                                                  Func<T, U> selector)
{
  if (@this is IOrderedEnumerable<T>) return @this.ThenBy(selector);

  return @this.OrderBy(selector);
}

This isn't exactly the same you're doing, but unless you're working on an enumerable that has been ordered before, it's going to work the same way.

like image 182
Luaan Avatar answered Sep 19 '22 15:09

Luaan