Stefan Steiger
Stefan Steiger

Reputation: 82216

Order a List by a arbitrary sort expression?

Question:

I have a generic list, like this:

System.Collections.Generic.List<Question> myquestions = new System.Collections.Generic.List<Question>();

And I have a paging example, using a LINQ table acquried from database, doing this for paging:

var questions = context.Questions
    .OrderBy(sidx + " " + sord)
    .Skip(pageIndex * pageSize)
    .Take(pageSize);

Right now, for paging my populated from code list, I have:

var questionss = myquestions
    .OrderBy(x => x.Id)
    .Skip(pageIndex * pageSize)
    .Take(pageSize);

And what I want is being able to order "myquestions" by a string as in the above example. Is that possible?

Upvotes: 2

Views: 4008

Answers (5)

Stefan Steiger
Stefan Steiger

Reputation: 82216

Bahaha, now I'm gonna cry:

Trying to implement dtb's solution, I saw the problem:

OrderByField<T>(IQueryable<T> q,

Returns IQueryable while inputting IQueryable... lol bs. So, the real question is how to convert List to be iQueryable.

Which, in fact is dead simple:

var list = new List<T>(); 
var queryable = list.AsQueryable(); 

then

queryable.OrderBy(sidx + " " + sord);

So the final solution is as trivial as:

myquestions.AsQueryable().OrderBy(sidx + " " + sord).Skip(pageIndex * pageSize).Take(pageSize);

Which also means Linq.Table implements IQueryable, which makes sense IMHO.

Edit:
Note:
This requires reference to: Dynamic.dll (not System.Dynamic.dll) as well as

using System.Linq.Dynamic;

If you don't reference Dynamic.dll, or don't declare the using directive, you'll get an error on AsQueryable().

Upvotes: 3

Guffa
Guffa

Reputation: 700442

You can chain the extension methods in separate statements thanks to the lazy execution, which means that you can add different sorting depending on a condition:

IOrderedQueryable<Question> sorted;
switch (sort) {
  case "Id":  sorted = myquestions.OrderBy(x => x.Id);
  case "Name": sorted = myquestions.OrderBy(x => x.Name);
  case "Size": sorted = myquestions.OrderBy(x => x.Size);
  case "Id Desc":  sorted = myquestions.OrderByDescending(x => x.Id);
  case "Name Desc": sorted = myquestions.OrderByDescending(x => x.Name);
  case "Size Desc": sorted = myquestions.OrderByDescending(x => x.Size);
  default: throw new NotImplementedException();
}
var questions = sorted.Skip(pageIndex * pageSize).Take(pageSize);

You can even add a secondary sorting (or as many as you like, after the first they are all the same):

IOrderedQueryable<Question> sorted;
switch (sort) {
  case "Id":  sorted = myquestions.OrderBy(x => x.Id);
  case "Name": sorted = myquestions.OrderBy(x => x.Name);
  case "Size": sorted = myquestions.OrderBy(x => x.Size);
  case "Id Desc":  sorted = myquestions.OrderByDescending(x => x.Id);
  case "Name Desc": sorted = myquestions.OrderByDescending(x => x.Name);
  case "Size Desc": sorted = myquestions.OrderByDescending(x => x.Size);
  default: throw new NotImplementedException();
}
switch (sort2) {
  case "Id":  sorted = sorted.ThenBy(x => x.Id);
  case "Name": sorted = sorted.ThenBy(x => x.Name);
  case "Size": sorted = sorted.ThenBy(x => x.Size);
  case "Id Desc":  sorted = sorted.ThenByDescending(x => x.Id);
  case "Name Desc": sorted = sorted.ThenByDescending(x => x.Name);
  case "Size Desc": sorted = sorted.ThenByDescending(x => x.Size);
}
var questions = sorted.Skip(pageIndex * pageSize).Take(pageSize);

Upvotes: 3

Niki
Niki

Reputation: 15867

You could look at Dynamic Linq. IIRC it was a sample that shipped with VS2008, I'm not 100% sure if it's still included in VS2010.

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1501163

One option is to create a dictionary from each possible ordering string to an appropriate delegate. For example:

Dictionary<string, Func<IEnumerable<Question>, IEnumerable<Question>> orderings =
    new Dictionary<string, Func<IEnumerable<Question>, IEnumerable<Question>>()
{
    { "Id",  questions => questions.OrderBy(x => x.Id) },
    { "Title",  questions => questions.OrderBy(x => x.Title) },
    { "Answer",  questions => questions.OrderBy(x => x.Answer) },
    { "Id Desc",  questions => questions.OrderByDescending(x => x.Id) },
    { "Title Desc",  questions => questions.OrderByDescending(x => x.Title) },
    { "Answer Desc",  questions => questions.OrderByDescending(x => x.Answer) },
};

Then you can find that mapping at execution time, and apply the function.

Upvotes: 1

Cheng Chen
Cheng Chen

Reputation: 43523

Please check my answer to another question on how to build a custom OrderBy predicate using Expression from a given String.

Upvotes: 2

Related Questions