18

I have a question about Linq / Lambda and the following issue:

I have two dictionaries, primary and secondary... These two dictionaries are defined as Key=string, Value=int. I need to trim down the primary dictionary if the KEYS intersect with secondary dictionary.

i.e.:

primaryDict = ["thing1", 33] ["thing2", 24] ["thing3", 21] ["thing4", 17] ["thing5", 12]

secondaryDict = ["thing1", 22] ["thing3", 20] ["thing4", 19] ["thing7", 17] ["thing9", 10]

resultDict = ["thing1", 33] ["thing3", 21] ["thing4", 17]

My attempt:

resultDict = primaryDict.Keys.Intersect(secondaryDict.Keys).ToDictionary(t => t.Key, t.Value);

This obviously does not work because the primaryDict.Keys.Intersect is returning a list of keys... how would I reestablish a new dictionary, or pair down the primary dictionary? Any help would be appreciated.

Nikhil Agrawal
  • 47,018
  • 22
  • 121
  • 208
Stewart Basterash
  • 223
  • 1
  • 2
  • 7

4 Answers4

31

You could do in this way:

resultDict =  primaryDict.Keys.Intersect(secondaryDict.Keys)
                              .ToDictionary(t => t, t => primaryDict[t]);

or, alternatively:

resultDict =  primaryDict.Where(x => secondaryDict.ContainsKey(x.Key))
                         .ToDictionary(x => x.Key, x => x.Value);

the latter maybe is slightly more efficient because avoids the creation of a throw-away collection (the one generated by the Intersect method) and does not require a second access-by-key to primaryDict.

EDIT (as per comment) :

resultDict =  
primaryDict.Where(x => secondaryDict.ContainsKey(x.Key))
           .ToDictionary(x => x.Key, x => x.Value + secondaryDict[x.Key]);
digEmAll
  • 56,430
  • 9
  • 115
  • 140
  • 2
    I think the last version is much better, as I don't think treating the dictionary as an IEnumerable will leverage the Dictionary, and will run in O(n) time. – Dave Bish May 21 '12 at 13:03
  • That worked great for what I'm doing... I used the second solution and everything is working as expected. You rock Dave! – Stewart Basterash May 21 '12 at 15:49
  • As a follow up... is it possible to sum the values in this same expression? – Stewart Basterash May 21 '12 at 17:12
  • @StewartBasterash: The values in primaryDict with the ones in secondaryDict having the same keys? – digEmAll May 21 '12 at 17:16
  • Yes... I am capturing and evaluating data across different domains. The different dictionaries maintain the data for a given domain... The key indicates an element within that domain, and the value is how it was presented in that domain... I am attempting to do some additional calculation... I need to do statistical analysis on a given element (key), across multiple domains (dictionary), based on values for each key... I hope this makes sense? – Stewart Basterash May 21 '12 at 17:43
  • Got it... That makes sense... sorry for my ignorance... I am new to writing Lambda in .NET, but I'm really loving this stuff for the things that I do with data mining... – Stewart Basterash May 21 '12 at 17:50
  • @StewartBasterash: don't worry, LINQ and lambda expressions can be pretty difficult at the beginning ;) – digEmAll May 21 '12 at 18:47
  • how can i do this based on values.?? Intersection is working but i want to convert it to dictionary.. So .ToDictionary(t => t, t => primaryDict[t]); part gives error – SRJ Oct 05 '16 at 06:20
  • @SRJ: if you're intersecting values you can't use `primaryDict[value]`, but maybe I didn't get your problem... anyway I suggest you to open a new question – digEmAll Oct 05 '16 at 06:54
  • Is this faster than linear? How fast is this? – theonlygusti Nov 12 '21 at 02:06
4

You can still use primaryDict within your Linq statement since you are creating a new dictionary, which only gets assigned to your variable once it is created:

resultDict = primaryDict.Keys
                        .Intersect(secondaryDict.Keys)
                        .ToDictionary(t => t, primaryDict[t]);
BrokenGlass
  • 158,293
  • 28
  • 286
  • 335
2

Untested:

resultDict = primaryDict.Keys.Intersect(secondaryDict.Keys).ToDictionary(t => t.Key, primaryDict[t.Key]);
Steve Czetty
  • 6,147
  • 9
  • 39
  • 48
0

If you want to select out an object with the "value" of both dictionaries, because that what you probably want, the you can try something like this. Assuming that the keys for both dictionaries are the same i.e. that map each together, like a GUID between two systems

dictA.Keys.Intersect(dictB.Keys).Select(x => new MyMappingClass
{
    dictAValue= dictA[x], dictBValue= dictB[x]
})
Atif Rehman
  • 417
  • 6
  • 6