views:

58

answers:

3

Assume I have generic list L of some type in c#. Then, using linq, call OrderBy() on it, passing in a lambda expression.

If I then re-assign the L, the previous order operation will obviously be lost.

Is there any way I can 'save' the lambda expression I used on the list before i reassigned it, and re-apply it?

+2  A: 

Use a Func delegate to store your ordering then pass that to the OrderBy method:

Func<int, int> orderFunc = i => i; // func for ordering
var list = Enumerable.Range(1,10).OrderByDescending(i => i); // 10, 9 ... 1
var newList = list.OrderBy(orderFunc); // 1, 2 ... 10

As another example consider a Person class:

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Now you want to preserve a sort order that sorts by the Name property. In this case the Func operates on a Person type (T) and the TResult will be a string since Name is a string and is what you are sorting by.

Func<Person, string> nameOrder = p => p.Name;

var list = new List<Person>
{
    new Person { Id = 1, Name = "ABC" },
    new Person { Id = 2, Name = "DEF" },
    new Person { Id = 3, Name = "GHI" },
};

// descending order by name
foreach (var p in list.OrderByDescending(nameOrder))
    Console.WriteLine(p.Id + ":" + p.Name);

// 3:GHI
// 2:DEF
// 1:ABC

// re-assinging the list
list = new List<Person>
{
    new Person { Id = 23, Name = "Foo" },
    new Person { Id = 14, Name = "Buzz" },
    new Person { Id = 50, Name = "Bar" },
};

// reusing the order function (ascending by name in this case)
foreach (var p in list.OrderBy(nameOrder))
    Console.WriteLine(p.Id + ":" + p.Name);

// 50:Bar
// 14:Buzz
// 23:Foo

EDIT: be sure to add ToList() after the OrderBy calls if you need a List<T> since the LINQ methods will return an IEnumerable<T>.

Ahmad Mageed
Very cool. Thankyou for such a comprehensive answer.
maxp
@maxp great, glad that helped! :)
Ahmad Mageed
A: 
Func<List<int>, IEnumerable<int>> applyQuery = L => L.OrderBy(i => -i);

List<int> source = new List<int>(){1, 2, 5};            
IEnumerable<int> query = applyQuery(source);

source = new List<int>() { 1, 2, 3 };
query = applyQuery(source);

foreach (int x in query)
{
  Console.WriteLine(x);
} 

Output:

3
2
1
David B
+1  A: 

Calling ToList() or ToArray() on your IEnumerable<T> will cause it to be immediately evaluated. You can then assign the resulting list or array to "save" your ordered list.

Phong