views:

219

answers:

3

Hi there,

i am trying to do a groupby in linq, basically i have a list ( along list - around 1000 entries) and i wish to groupby Description.

The entries are vehicles, so hence there are 50 or so Ford Mondeos

My query is pretty simple, no joins (yet :-) ) but it brings back a list including 50 Ford Mondeos, i wanted it to group them so there is only 1 entry.

I am only selecting Description, i am not selecting the IDs which would be different, but in LinqPad it returns the desc and i can see 50 ford mondeos that are all the same in description - letter for letter.

What am i doing wrong?

from v in dc.Vehicles
   group v by v.Description into g1
from y in g1
   orderby y.Description 
select new
{
     Desc = y.Description 
};

EDIT

It now brings back just 1 record for each ford mondeo, this was my test to ensure it worked but i need to expand on this, again it should only bring back 1 record each for ford mondeo as i have checked they all have same number of doors, categor, model id etc..

from v in dc.Vehicles
  group v by v.Description into g1
orderby g1.Key
  select new
  {
     Desc = g1.Key,
     CategoryId = g1.CategoryId,
     MakeId = g1.MakeId,
     ModelId = g1.ModelId,
     Doors = g1.Doors,
  };

Of the course the above doesn't work it doesn't find all the other fields i.e. CategoryId... i tried separating the group by and adding a comma for the other fields..

I think i have a little confusion over the key, i understand that this is the key but if you are grouping on more than 1 fields then potentially you would have more than 1 key..

Any ideas?

+4  A: 

You're using a second "from" which is causing the problem. Try this:

from v in dc.Vehicles
group v by v.Description into g1
orderby g1.Key
select new
{
     Desc = g1.Key
};

Conceptually, a group like this consists of a "sequence of sequences" - one subsequence per group, with all the items matching that group. Each subsequence has a key - the description in this case.

Your "from" clause was basically saying, "for each group, get me all the elements in the group" - effectively ungrouping them again :) Typically you'd perform some sort of aggregation on the group, e.g. for the final part:

select new
{
     Desc = g1.Key,
     Oldest = g1.Min(x => x.Date),
     Newest = g1.Max(x => x.Date)
};

EDIT: To group on more than one field, use an anonymous type:

group v by new { v.Description, v.Doors, v.Model } into g1

That anonymous type will then form the key.

To get any field within a record, you could try:

select new { RandomField = g1.First().RandomField, Description = g1.Key, // etc }

That logically takes the first record in the subsequence. I don't know whether it'll work for LINQ to SQL though - I know it would in LINQ to Objects, but I've no idea what the SQL equivalent would be. Even if it does work, it may well be incredibly expensive. I suspect that grouping by a composite key (via an anonymous type) is the way to go here.

Jon Skeet
Thanks Jon, a big help! .this worked great, it brings back 1 record for all ford mondeos, I don't fully understand key, but can i group on my than 1 field in Linq like in sql? Then what happens to key? I will update my question to show you what i am doing
mark smith
Question updated
mark smith
I did get this to work but is this the best way of doing it? a select within a select?? CategoryId = g1.Select(x => x.CategoryId) . I must admit it worked... SO am i forced to call the method select to get a field with the grouping?? And of course what if 1 mondeo as 5 dorrs and 1 has 4 doors but with the same description - i would need 2 records as technically they are different which is why it seems to me you should be able to group on more than 1 field, I think i am still stuck in sql world :-) !!!
mark smith
Wow - thanks jon! Yep now i see you get extra properties off the .KEY .. this is really great... a big big thank you!!!
mark smith
A: 

Group bys are not used to get unique rows, but to group columns when there are aggregate expressions like sum, avg, count, and so forth.

Rap
Thank bpayne, yes a bit of an error with my terminology there, thanks for the correction
mark smith
+1  A: 

If you just want the keys (the fields you're grouped on) you need to do something like this...

from v in dc.Vehicles
   group v by v.Description into g1
select g1.Key;
Jason Punyon