1

(Converting a Dictionary to ILookup is not very nice: How do I convert a Dictionary to a Lookup? )

I want to have an interface for my container class with the following method:

ILookup<Type, Entry> Query ( IEnumerable<QueryClause> query );

Each query clause specifies which and how many (and some more details) of a special kind of Entry should be taken out of the underlying container.

My implementation currently looks something like this:

var result = new Dictionary<Type, List<Entry>>();

foreach(var clause in query)
{
    var clauseResult = FulfillClause(clause);
    result.Add(clause.Type, clauseResult);
}

return result.ToLookup(); // here it is

Is there any chance this method my return ILookup directly? Unfortunately it does not support yield return.

Community
  • 1
  • 1
D.R.
  • 20,268
  • 21
  • 102
  • 205
  • Your code doesn't appear to be using `yield return`, so it's hard to see how that's relevant... and you haven't told us anything about `query` or `FulfillClause`. – Jon Skeet Nov 29 '13 at 18:00
  • I would like to replace the result.Add line with yield return, however, that is not possible as C# does not support yield return for ILookup (only IEnumerable) – D.R. Nov 29 '13 at 18:01

1 Answers1

4

I'm not entirely sure why you have the dictionary in the first place. Does this work for you?

return query.ToLookup(clause => clause.Type, clause => FullFillClause(clause));

It doesn't comply with the ILookup<Type, Entry> interface but neither does the code you provide so I can't be certain about what you actually want.

Here's attempt after re-reading the question:

return query.SelectMany(c => FulfillClause(c).Select(r => new {Type=c.Type, Result=r}))
            .ToLookup(o => o.Type, o => o.Result);

It's a translation of @JonSkeet's linked answer.

To test without knowing the details of all the types & methods, I used this:

Func<List<int>> f = () => new List<int>() {1, 2, 3};
var query = new List<Type> {typeof (int), typeof (string)};

var l = query.SelectMany(t => f().Select(n => new {Type = t, Result = n}))
    .ToLookup(o => o.Type, o => o.Result);

If you control all the code, you could restructure some of it to enhance readability:

return query.SelectMany(c => c.Fulfill())
            .ToLookup(res => res.Type, res => res.Value);

...
// You will need to create the ClauseFulfillment type yourself
public IEnumerable<ClauseFulfillment> FulFill()
{
   var results = // whatever FulfillClause does
   foreach(var r in results)
      yield return new ClauseFulfillment {Type = Type, Result = r}; 
}
Austin Salonen
  • 49,173
  • 15
  • 109
  • 139
  • Why does my code not comply with the ILookup interface? Given the dictionary and the ToLookup extension method given in the linked thread I fulfill the interface. – D.R. Nov 29 '13 at 18:31
  • Please take a look at the linked thread, thank you. It shows an extension method which conveerts Dictionary> into Lookup. – D.R. Nov 29 '13 at 18:39
  • Thank you for your big effort! +1! However, I'm not so sure if the new code is really more readable than my original effort. Thank you anyways. I was hoping C# allows me to do some yield return stuff :-) – D.R. Nov 29 '13 at 19:32
  • @D.R. -- you're welcome! If you control all the code, I've updated my answer. – Austin Salonen Nov 29 '13 at 19:46