1

Possible Duplicate:
Recreating a Dictionary from an IEnumerable

When using the Where method on a dictionary of type Dictionary<TKey, TValue> you ends up with a IEnumerable<KeyValuePair<TKey, TSource>> and that is breaking the datatype that I have choose at the beginning. I would like to return a dictionary.

Maybe I am not using the correct filter function. So how do you usually filter element from a dictionary?

Thanks

Community
  • 1
  • 1
mathk
  • 7,973
  • 6
  • 45
  • 74

4 Answers4

2

IDictionary<TKey, TValue> actually extends IEnumerable<KeyValuePair<TKey, TValue>>. This is why you can use LINQ operators on an IDictionary<TKey, TValue> in the first place.

However, LINQ operators return IEnumerable<T> which are meant to provide deferred execution, meaning the results aren't actually generated until you start iterating through the IEnumerable<T>.

The IEnumerable<T> implementation which is provided by IDictionary<TKey, TValue> comes by way of the ICollection<T> interface (where T is a KeyValuePair<TKey, TValue>), which means that if LINQ were to return IDictionary<TKey, TValue> instead of IEnumerable<KeyValuePair<TKey, TValue>> then it would have to materialize the list, violating it's principals (hence the IEnumerable<KeyValuePair<TKey, TValue>> return value).

Of course, the way around it is to call the ToDictionary extension method on the Enumerable class (as others have mentioned), but a little back-story never hurts.

casperOne
  • 73,706
  • 19
  • 184
  • 253
  • IMHO it is not a good idea to have dictionary "inherit" all the LINQ query especially that deferred execution is not an interesting feature to have for a dictionary. A cleaner API with proper method that accept closure would have been better. – mathk Jun 27 '12 at 12:55
  • @mathk It's not really an issue with the dictionary, but the fact that it implements `ICollection`; what you're suggesting is that anything that implements `ICollection` would materialize it's result set after *each* operation. That's *highly* inefficient as you'd have to materialize the `ICollection` after *each* query operation (*every* `select`, `where`, `let`, etc.). – casperOne Jun 27 '12 at 13:04
  • It is not what I am saying. I am saying the it should not inherit all LINQ qyuery. It does not make a lot of sens to have query operation on dictionary. Especially that query expression are lazy evaluated and that is not as pretty as the Haskell lazy evaluation. – mathk Jun 27 '12 at 13:27
  • @mathk I see what you're saying, but then you'd either have to a) remove the `ICollection` implementation from `IDictionary` (which doesn't make much sense) or b) find a way to tell type inference to not be used for specific derivations of a type. Either proposition isn't too appealing, IMO. – casperOne Jun 27 '12 at 13:29
  • Yes, I concider that the Dictionary API is not well implemented I rather have Dictionary implement an interface like: `interface IDctionary { Dictionary Collect(Func collector); Dictionary Reject(Func predicate); Dictionary Select(Func predicate); // The correct meaning of select void Do(Func block); ... }` – mathk Jun 27 '12 at 13:38
  • Seeing that the method `.ToDictionary()` have been implemented seems a big bodgy smell. Dictionary shouldn't have implement the ICollection at the first place. Or the IEnumerable part of ICollection – mathk Jun 27 '12 at 13:44
1

How about .ToDictionary() in the end?

Bali C
  • 30,582
  • 35
  • 123
  • 152
Nikhil Agrawal
  • 47,018
  • 22
  • 121
  • 208
1

You can use Where(), and follow with ToDictionary():

var newDict = yourDict.Where(pair => SomePredicateFrom(pair))
                      .ToDictionary(pair => pair.Key, pair => pair.Value);
Frédéric Hamidi
  • 258,201
  • 41
  • 486
  • 479
  • I usually avoid To*() method. Especially this one who take 2 lambda. It sound like I am using a sword for cutting the bread. But if the API force me to do it that way, I have no choice. – mathk Jun 25 '12 at 12:33
1

Use .ToDictionary(); in your LINQ expression.

Omar
  • 16,329
  • 10
  • 48
  • 66