TalkingCode
TalkingCode

Reputation: 13557

Use OrderBy in a LINQ predicate?

In my code I need to sort a collection either by Price or by Rating.TotalGrade and as you can see both LINQ querys are almost the same statement with only a minor difference.

I was thinking about using a LINQ predicate instead but as you can see the the orderby is the main difference and I found no sample using orderby in a query. Is it possible or are there other ways to shorten my code, Maybe there will be even more conditions in the future.

if (CurrentDisplayMode == CRSChartRankingGraphDisplayMode.Position)
{
    this.collectionCompleteSorted = new List<Result>(from co in collection
                                    where co.IsVirtual == false
                                    orderby co.Price, co.CurrentRanking
                                    select co);
}
else if (CurrentDisplayMode == CRSChartRankingGraphDisplayMode.Grade)
{
    this.collectionCompleteSorted = new List<Result>(from co in collection
                                    where co.IsVirtual == false
                                    orderby co.Rating.TotalGrade, co.CurrentRanking
                                    select co);
}

Upvotes: 2

Views: 8485

Answers (4)

Diego
Diego

Reputation: 20194

var q = collection.Where(co => !co.IsVirtual);

if (CurrentDisplayMode == CRSChartRankingGraphDisplayMode.Position)
{
    q = q.OrderBy(co => co.Price).ThenBy(co => co.CurrentRanking);
}
else if (CurrentDisplayMode == CRSChartRankingGraphDisplayMode.Grade)
{
    q = q.OrderBy(co => co.Rating.TotalGrade).ThenBy(co => co.CurrentRanking);
}

this.collectionCompleteSorted = q.ToList();

Upvotes: 1

Euphoric
Euphoric

Reputation: 12849

You can easily make use of deffered nature of LINQ and ability to easily compose queries.

Probably using code like this:

        var baseQuery = from co in collection where !co.IsVirtual select co; // base of query
        IOrderedEnumerable<Result> orderedQuery; // result of first ordering, must be of this type, so we are able to call ThenBy

        switch(CurrentDisplayMode) // use enum here
        { // primary ordering based on enum
            case CRSChartRankingGraphDisplayMode.Position: orderedQuery = baseQuery.OrderBy(co => co.Price);
                break;
            case CRSChartRankingGraphDisplayMode.Grade: orderedQuery = baseQuery.OrderBy(co => co.TotalGrade);
                break;
        }

        this.collectionCompleteSorted = orderedQuery.ThenBy(co => co.CurrentRanking).ToList(); // secondary ordering and conversion to list

Its easy to understand and avoids converting to list until the very end.

Upvotes: 3

Brad Christie
Brad Christie

Reputation: 101614

Why not just grab the values (less the sort), then (as it appears) use a case to order the results?

// build your collection first
var items = from co in collection
            where !co.IsVirtual
            select co;

// go through your sort selectors
select (CurrentDisplayMode)
{
  case CRSChartRankingGraphDisplayMode.Position:
    this.collectionCompleteSorted = items.OrderBy(i => i.Price).ThenBy(j => j.CurrentRanking).ToList();
    break;
  case CRSChartRankingGraphDisplayMode.Grade:
    this.collectionCompleteSorted = items.OrderBy(i => i.TotalGrade).ThenBy(j => j.CurrentRanking).ToList();
    break;
  ...
  //default: // maybe you want this, too
}

Upvotes: 1

mservidio
mservidio

Reputation: 13057

If just your order by is different, than return your result into this.collectionCompleteSorted, and then do this.collectionCompleteSorted.OrderBy() when you enumerate through the data.

this.collectionCompleteSorted = new List<Result>(from co in collection 
                                                             where co.IsVirtual == false                                                                  
                                                             select co);

foreach (var obj in this.collectionCompleteSorted.OrderBy(c => c.Price).ToList())
{
    // do something
}

And remove the order by remove your current linq query.

If the query is just being executed once, than you can leave off the .ToList() from the linq query in the example above. When ToList is called, this causes the query to be executed immediately, where if the OrderBy is implemented in a later call to the collection and a ToList is also, than the query would actually be executed on the database server with an order by statement, offloading the ordering from the code to the database. See http://blogs.msdn.com/b/charlie/archive/2007/12/09/deferred-execution.aspx

Upvotes: 1

Related Questions