Reputation: 23187
I have an array that stores the order that I want to sort a list by.
SortOrderArray: "Color", "Volume", "Weight"
So I want to order my list by Color, Volume, then Weight
MyList.OrderBy(a=>a.Color).ThenBy(a=>a.Volume).ThenBy(a=>a.Weight).ToList();
So that's pretty good. Now, I want to be able to write a function that does this sorting based on the sortOrder array I send in:
public List<row> GetSortedList(List<row> list, string[] sortOrder){
???
}
I can't figure out how to do this without writing a linq query for every combination of sortOrders (27 different queries just seems like the worst way to accomplish this, and has a fairly high possibility of me making a tiny mistake). I would like to be able to just write 3 linq queries that reorders the list according to each of the 3 sorting methods, something like this:
switch(sortOrder[0]){
Sort by the first sort method
}
switch(sortOrder[1]){
Sort by the second sort method
}
switch(sortOrder[2]){
Sort by the third sort method
}
But if I try doing the above code, it just resorts it each time, instead of doing sub-sorts after the one above it. Hope that is clear, any help would be appreciated.
Upvotes: 0
Views: 153
Reputation: 174319
I guess, you are not using the return value of the order clauses.
public List<row> GetSortedList(List<row> list, string[] sortOrder)
{
IOrderedEnumerable<row> result = null;
bool first = true;
foreach(sortClause in sortOrder)
{
switch sortClause
{
case "Color":
if(first)
result = list.OrderBy(x => x.Color);
else
result = result.ThenBy(x => x.Color);
break;
// the other cases
}
first = false;
}
return result.ToList();
}
Something like that.
Upvotes: 0
Reputation: 2972
Have a look at this post from Scott Guthrie: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
Upvotes: 0
Reputation: 113402
Using Dynamic LINQ, you can do something like:
public List<row> GetSortedList(List<row> list, string[] sortOrder)
{
// argument-validation, including testing that
// sort-order has at least 1 item.
return sortOrder.Skip(1)
.Aggregate(list.AsQueryable().OrderBy(sortOrder.First()),
(query, nextSortTerm) => query.ThenBy(nextSortTerm))
.ToList();
}
Essentially: OrderBy
the first sort-term, ThenBy
the remaining.
EDIT: Added an AsQueryable
call to make Dynamic LINQ work on IEnumerable<T>
Upvotes: 0
Reputation: 156524
If you have a limited number of possible fields to sort by, a switch might be the best solution. If you're looking for something that scales, you'll have to generate a lambda expression on the fly, and use reflection to call the appropriately-typed .OrderBy
and .ThenBy
methods.
Upvotes: 0
Reputation: 35540
Two things. You need a sort method that performs a "stable sort" - it keeps the existing order of items with identical keys. And then you need to call it in reverse order of your sort criteria , so that the primary sort is the last one you do.
Upvotes: 2