views:

48

answers:

2

I would like to sort a collection based on a subcollection property.

//the subcollection
public class Salary
{
   public int SalaryId {get;set;}
   public int SalaryYear {get;set;}
   public double SalaryValue {get;set;} //this is the field we want to sort the parent collection "Person"
}

//the main collection
public class Person
{
   public int PersonId {get;set;}
   public string PersonName {get;set;}
   public List<Salary> Salaries {get;set;}
}

Below just for testing purpose, I'm preparing my collection of person with Salaries inner collections each one:

List<Person> people = new List<Person>();
//add two salaries for Junior
people.Add(new Person { PersonId = 1, PersonName = "Junior" });
people[0].Salaries.Add(new Salary { SalaryId=1, SalaryYear=2011, SalaryValue=80000 });
people[0].Salaries.Add(new Salary { SalaryId=2, SalaryYear=2010, SalaryValue=70000 });

//add two salaries for Johanna
people.Add(new Person { PersonId = 2, PersonName = "Johanna" });
people[0].Salaries.Add(new Salary { SalaryId=3, SalaryYear=2011, SalaryValue=40000 });
people[0].Salaries.Add(new Salary { SalaryId=4, SalaryYear=2010, SalaryValue=30000 });

Now we want to sort the people collection, but using their inner collection SalaryValue as parameter.

How can I sort List but using LINQ / Lambda expressions on Salaries inner collection?

So I would have:

PersonName: Johanna, SalaryValue=30000, SalaryYear=2010
PersonName: Johanna, SalaryValue=40000, SalaryYear=2011
PersonName: Junior, SalaryValue=70000, SalaryYear=2010
PersonName: Junior, SalaryValue=80000, SalaryYear=2011
+2  A: 

To me, that looks like:

var query = from person in people
            from salary in person.Salaries
            orderby salary.SalaryValue
            select new { person, salary };

foreach (var pair in query)
{
    Console.WriteLine(pair);
}

Note that you're not really sorting a collection of people - you're sorting a collection of (person, salary), which is what the flattening effect of having two from clauses does.

(The above won't provide exactly the same output, but once you've got the person and their salary, you can get at the other values.)

Jon Skeet
This sorts on salary, independent of the outer collection. It's ambiguous if the poster cares if the list contains `Johanna:30000, Junior:70000, Johanna:75000, Junior:80000` or if he wants it to be `Johanna:30000, Johanna:75000, Junior:70000, Junior:80000`
Marc
@Marc: That's true... but as it's been accepted, I assume this is what was wanted.
Jon Skeet
A: 

It looks like Jon's logic is correct, but the sample code doesn't match the OP's. It should probably be more like this:

var query = from person in people
            from salary in person.Salaries
            orderby salary.SalaryValue
            select new { person.PersonName, salary.SalaryValue, salary.SalaryYear };

foreach (var tuple in query)
{
    Console.WriteLine(tuple);
}
Steven Sudit
Thanks, I've fixed my orderby clause. I haven't changed the projection - I figure once you've got the person and salary, you can print whatever bits you want and leave the rest.
Jon Skeet
both comments were great, thank you guys
Junior Mayhé
@Jon: Thanks for putting up with my nitpicking. :-)
Steven Sudit