tags:

views:

57

answers:

1

I basically have a table with headers that I read in from a DB using linq in C#. Of these headers, there is always at least one that is always the same; Total and I want it to always be on the right.

So here is sort of how my data is laid out:

Data
{
   Label,
   Value,
   Age  //Not used initially
}

Sample Data:

{"Dog", 7}
{"Cat", 3}
{"Other", 4}
{"Total", 14}

I'd like to order the labels in this order; the actual animal names are sorted by their value in descending order and Total is appended to the end:

"Dog", "Other", "Cat", "Total"

How do I do this in Linq. How do I order an attribute based upon the value of another attribute?

Once I have the order of the headers, is there an easy way to order future rows based upon the already determined order. If I want to initially find headers where(x=>x.Age > 20) how can I sort the Labels in where(x=>x.Age <= 20) based upon the same ordering as the >20 set?

+4  A: 

This query should work:

var query = from row in table
            let ignore = row.Label == "Total"
            orderby ignore, row.Value descending
            select row.Label;

//and corresponding lambda version
var lquery = table.OrderBy(row => row.Label == "Total")
                  .ThenByDescending(row => row.Value)
                  .Select(row => row.Label);

Note: it isn't entirely necessary to create a ignore variable, it could be placed directly in the orderby clause. This way, it makes it more readable.

Not sure what you are asking in your second question.


edit:
In response to your comment, it would depend on how you wanted the sorting to work, at least written like this. This works well if there is only one row in the table that you want to completely ignore. Not so much if you had more than one. The problem being that among the "ignored" rows, will be sorted by the original sorting as well (in this case, by Value). A naive way to add another row is to add to the ignore condition.

var query = from row in table
            let ignore = row.Label == "Total" || row.Label == "Cost"
            orderby ignore, row.Value descending
            select row.Label;

To have a specific ordering among the "ignored" rows, it would require a somewhat more complex query:

var query = from row in table
            let ignore = row.Label == "Total" || row.Label == "Cost"
            let ignoreorder = row.Label == "Cost" ? 1 : 0
            orderby ignore, ignoreorder, row.Value descending
            select row.Label;

//and corresponding lambda version
var lquery = table.OrderBy(row => row.Label == "Total" || row.Label == "Cost")
                  .ThenBy(row => row.Label == "Cost" ? 1 : 0)
                  .ThenByDescending(row => row.Value)
                  .Select(row => row.Label);
Jeff M
The `ignore` part is clever... +1
Thomas Levesque
What would the syntax look like if I had more than 1 "ignore" column. Like Total and Cost. And I always wanted Cost to be after ignore. Also, what would the lambda expression syntax for this look like? This solved my first question. Thanks. I'll work on the second and perhaps clarify further in another question.
Harry
EXCELLENT. Thanks for the clarity and providing lambda and whatever the other style is called.
Harry