Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Selective ordering with LINQ, partial ordering

Let's say I have a list of objects:

var items = new {
    new { Order = 0 },
    new { Order = 1 },
    new { Order = -1 },
    new { Order = 3 },
    new { Order = 2 },
    new { Order = -1 }
};

I need to order it so that items with Order > -1 be on top of the list ordered by Order ascending, and remaining items with Order == -1 were following them.

Is there a more elegant way of doing this than using Conact() and Where() clauses:

var orderedItems = items.Where(x => x.Order > -1).OrderBy(x => x.Order)
                   .Conact(items.Where(x => x.Order == -1);

So that after sorting this list would look like:

var items = new {
    new { Order = 0 },
    new { Order = 1 },
    new { Order = 2 },
    new { Order = 3 },
    new { Order = -1 },
    new { Order = -1 }
};

Also items list in actual scenario is already a complex IQueryable<T> object. That's why I am trying to find the most optimal way of doing such selective ordering.

like image 875
Konstantin Tarkus Avatar asked Feb 17 '10 15:02

Konstantin Tarkus


3 Answers

You could try this - it produces the result you expect:

items.OrderBy(x.Order => x.Order == -1).ThenBy(x.Order => x.Order);
like image 101
Leom Burke Avatar answered Oct 06 '22 00:10

Leom Burke


As Mike mentioned, in your example, it would work automatically, but say we wanted to get all -1 elements first and then sort remaining elements in a descending order. This can be done using a nice trick. You can use multiple keys when ordering elements. The first key can be a Boolean value which will be false for all -1 values (so they will be first) and true for all other values (so they won't be reordered). The second key can be whatever you want to order the remaining elements. For example:

var nums = new int[] { -1, 4, 2, 3, -1, 4, 7 };
var q = from n in nums
        orderby n != -1, n descending
        select n;

It will first yield all values for which n != -1 is false and then all elements ordered using n descending so you'll get:

-1, -1, 7, 4, 4, 3, 2

This works in general when you need to handle some elements especially in the ordering - you just need to provide the right ordering keys.

like image 36
Tomas Petricek Avatar answered Oct 06 '22 00:10

Tomas Petricek


If you order by ascending, -1 should already be at the top of the list, because it is the smallest value.

However, more generally, if you still wanted to apply different sorting to subsets of the data, I don't think there would be a more elegant way, because that's exactly what you are doing and the union is logically accurate. You're trying to pull two seperate subset of the data out, sort them differently, and then merge them together, which is one of the things what I union is to be used for.

like image 35
Mike Mooney Avatar answered Oct 05 '22 23:10

Mike Mooney