23

Linq newbie here, struggling with my first GroupBy query.

I have a list of objects of type KeywordInstance which represents a keyword, and the ID of the database record to which the keyword was applied.

Keyword      RecordID
macrophages  1
macrophages  2
cell cycle   3 
map kinase   2
cell cycle   1

What I want is a collection of all keywords, with a list of the RecordIDs to which each keyword was applied.

Keyword     RecordIDs 
macrophages 1, 2
cell cycle  1, 3
map kinase  2

I tried using Linq to get it into a new object. I only managed to get the distinct keywords.

var keywords = allWords .GroupBy(w => w.keyword) .Select(g => new {keyword = g.Key});

The problem is that I can't seem to get the values of g in any way. g is of the type IGrouping<String, KeywordInstance> and by documentation, it only has the property Key, but not even the property Value. All the examples I have seen on the Internet for groupby just tell me to select g itself, but the result of

var keywords = allWords
    .GroupBy(w => w.keyword)
    .Select(g => new {keyword = g.Key, RecordIDs = g});

is not what I want.

screenshot of result

Any try to get something out of g fails with the error message System.Linq.IGropuing<string, UserQuery.KeywordInstance> does not have a definition for [whatever I tried].

What am I doing wrong here?

AlexB
  • 7,302
  • 12
  • 56
  • 74
Rumi P.
  • 1,688
  • 3
  • 23
  • 31
  • I can imagine that this question is a duplicate, but I must have searched for the wrong keywords, at least the search results I found did not help me. – Rumi P. Nov 06 '13 at 13:12
  • I dont see the problem-- you have a key, and all the records belonging to that key? What where you expecting the records of `g` to look like :) ? – Jens Kloster Nov 06 '13 at 13:16
  • @JensKloster I don't care what the records of g look like. What I need is a data structure which maps the list of integers '{3, 169, 2179, 2188, 2334, 2389, 2496}' to the key 'FACTOR RECEPTOR'. I thought I would use groupby, and obviously used it wrong, getting g out of it instead of what I needed. So the question is, how do I use it right? – Rumi P. Nov 06 '13 at 13:22

3 Answers3

39

I think you are close to you solution.

var keywords = allWords
    .GroupBy(w => w.keyword)
    .Select(g => new 
           { 
              keyword = g.Key, 
              RecordIDs = g.Select(c => c.ID)
           });

Just Select the records you need.
The reason you are seeing the Keyword-column as well as the ID-column, is becuase it's part of g

Jens Kloster
  • 11,099
  • 5
  • 40
  • 54
  • thank you, I was trying to do it with something like RecordIDs = g.Values.ID and never thought of using a nested query on g. – Rumi P. Nov 06 '13 at 13:35
  • This does not seem to work when querying with Entity Framework. I had to do a "where" to select records by each group key. – ed22 Dec 29 '21 at 12:14
1
var keywords = allWords.GroupBy(w => w.keyword);

foreach (var itm in keywords)
{
   var list = itm.ToList();  
   //list returns all of the original properties/values objects from allwords.
   //itm.key returns w.keyword
}
John Foll
  • 121
  • 1
  • 10
0

One way to get values (but you lose the Key) is like the following:

var keywords = allWords
    .GroupBy(w => w.keyword)
    .Select(g => g.FirstOrDefault());

Or a cleaner approach:

var keywords = allWords
    .Select(w => w.keyword)
    .Distinct();
halfer
  • 19,824
  • 17
  • 99
  • 186
Hooman Limouee
  • 1,143
  • 2
  • 21
  • 43