sooprise
sooprise

Reputation: 23187

Doing multiple sorts across more than one line of code?

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

Answers (5)

Daniel Hilgarth
Daniel Hilgarth

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

Ani
Ani

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

StriplingWarrior
StriplingWarrior

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

AShelly
AShelly

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

Related Questions