tags:

views:

181

answers:

2
Q: 

Linq query

Hi,

I'm a big noob with Linq and trying to learn, but I'm hitting a blocking point here. I have a structure of type:

Dictionary<MyType, List<MyObj>>

And I would like to query with Linq that structure to extract all the MyObj instances that appear in more than one list within the dictionary.

What would such a query look like?

Thanks.

+1  A: 

You could do something like this:

var multipleObjs =
 MyObjDictionary.Values // Aggrigate all the List<MyObj> values into a single list
  .SelectMany(list => list) // Aggrigate all the MyObjs from each List<MyObj> into a single IEnumerable
  .GroupBy(obj => obj) // Group by the Obj itself (Or an ID or unique property on them if it exists)
  .Where(group => group.Count() >= 2) // Filter out any group with less then 2 objects
  .Select(group => group.Key); // Re-Select the objects using the key.

Edit
I Realized that this could also be read diffrently, such that it doesn't matter if the MyObj occurs multiple times in the same list, but only if it occurs multiple times in diffrent lists. In that case, when we are initally aggrigating the lists of MyObjs we can select Distinct values, or use a slightly diffrent query:

var multipleObjs =
 MyObjDictionary.Values // Aggrigate all the List<MyObj> values into a single list
  .SelectMany(v => v.Distinct()) // Aggrigate all distinct MyObjs from each List<MyObj> into a single IEnumerable
  .GroupBy(obj => obj) // Group by the Obj itself (Or an ID or unique property on them if it exists)
  .Where(group => group.Count() >= 2) // Filter out any group with less then 2 objects
  .Select(group => group.Key); // Re-Select the objects using the key.


var multipleObjs =
  MyObjDictionary.SelectMany(kvp => // Select from all the KeyValuePairs
   kvp.Value.Where(obj =>
    MyObjDictionary.Any(kvp2 => // Where any of the KeyValuePairs
     (kvp.Key != kvp2.Key) // Is Not the current KeyValuePair
     && kvp.Value.Contains(obj)))); // And also contains the same MyObj.
rmoore
Just SelectMany(v=>v) should do? (no need for v.Select(obj=>obj))
Marc Gravell
You're right. I just generally write explicitly what I'm selecting in more complex queries since it's easier for me to keep track of what is going on and then optimize it later, but forgot in this case. It's fixed now anyway.
rmoore
Count() will enumerate each group in its entirety. Using Skip(1).Any() is more efficient.
Bryan Watts
@Bryan Watts, Nice I don't use too much linq outside of simple Where and Select/Single/Default so it's good to learn more about some of the other options, thanks!
rmoore
+3  A: 
from myObjectList in myObjectDictionary.Values
from myObject in myObjectList.Distinct()
group myObject by myObject into myObjectGroup
where myObjectGroup.Skip(1).Any()
select myObjectGroup.Key

The Distinct() on each list ensures MyObj instances which repeat solely in the same list are not reported.

Bryan Watts