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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With