C
C#2y ago
Hercules

❔ How do you merging Dictionaries into one Dictionary?

Has anyone merged two dictionaries of same type into one?
I read something like this


var result = dictionaries.SelectMany(dict => dict)
.ToLookup(pair => pair.Key, pair => pair.Value)
.ToDictionary(group => group.Key, group => group.First());
I read something like this


var result = dictionaries.SelectMany(dict => dict)
.ToLookup(pair => pair.Key, pair => pair.Value)
.ToDictionary(group => group.Key, group => group.First());
Lookup(https://learn.microsoft.com/en-us/dotnet/api/system.linq.lookup-2?view=net-7.0). But will this code make the dictionary distinct (that values and keys don't repeat). I rather use same key and add the value from the dictionary i'm merging/joining. Maybe this option makes it ignore
new Dictionary<string, long>(StringComparer.OrdinalIgnoreCase);
new Dictionary<string, long>(StringComparer.OrdinalIgnoreCase);
Lookup Class (System.Linq)
Represents a collection of keys each mapped to one or more values.
40 Replies
Pokey
Pokey2y ago
This one got my curiosity going Short answer is yes, it does appear to, and I think I understand why Long answer is... Yea sure but theres gotta be a simpler way to achieve what you want to achieve? Because you're just taking the first instance of each key and discarding any others
Pokey
Pokey2y ago
See https://dotnetfiddle.net/rynDoT for my example demo of your code
Hercules @ C# | C# Online Compiler | .NET Fiddle
Hercules @ C# | Test your C# code online with .NET Fiddle code editor.
Hercules
Hercules2y ago
@Pokey I'll check it out. @Pokey It works fine. But since you had two dictionaries with A,a that means that your result should be.
A:aa
B:bb
C:cc
D:dd
E:ee
F:ff

<--- two a's because you had that value on two dictionaries
A:aa
B:bb
C:cc
D:dd
E:ee
F:ff

<--- two a's because you had that value on two dictionaries
Pokey
Pokey2y ago
Well no, that thing literally runs the code. The result you see was produced on the fly by running the code You do not have two of each, because you have chosen to take the .First() Nowhere have you concatenated anything
Hercules
Hercules2y ago
No, the result is correct! for the code. But what im looking for is 2 a's
Pokey
Pokey2y ago
I see Then you will want to not select the .First()
Hercules
Hercules2y ago
Let's remove it then. In you example.
Pokey
Pokey2y ago
Hercules @ C# | C# Online Compiler | .NET Fiddle
Hercules @ C# | Test your C# code online with .NET Fiddle code editor.
Pokey
Pokey2y ago
It works, but the important thing is, do you understand why it works?
Hercules
Hercules2y ago
Thanks i saw you append fix for each group item. Yeah i do, Tell me if im wrong. 1. I like to think select as a mapper and SelectMany same for Collections/lists/etc. Basiclly looping through all dictionaries 2. To lookup every values on keys (a collection of keys each mapped to one or more values. MSLEARN) 3. Make it to Dictionary, where group (kvp) goes through key and value but 4. instead of picking group.first we append each char in value (string) with a loop. So in short group is all keys and values. left side and right side.
group => group.Key () (left side) , group => right side
group => group.Key () (left side) , group => right side
I tried changing group.values but that dosen't go because of the lookup gets the values from key.
Pokey
Pokey2y ago
I think you pretty much have it It ultimately comes down to understanding what each function in the linq produces You may find it even easier to put each linq call into a variable and use your IDE's debugger to view the result after each step
Hercules
Hercules2y ago
Yes. A nice trick for that is to read it backwards. 1. create dict 2.Get value by lookup (with key) 3. loop through all dicts in listofDicts (selectMany)
Pokey
Pokey2y ago
I think there is probably an easier way to achieve what you want to ultimately but without more context it would be hard to know
Hercules
Hercules2y ago
I think this is the simplest way to do it. Your example was perfect. i .net fiddle
Pokey
Pokey2y ago
well I mean the "simplest" way would be to foreach each dictionary, foreach each item in that dictionary and then have an output dictionary which you use to check key existence and assemble with .Add
Hercules
Hercules2y ago
Something like this?
foreach(var dict in listOfDicts)
foreach (var kvp in dict)
{
if (newDict.ContainsKey(kvp.Key))
{
newDict[kvp.Key] += kvp.Value;
}
else
{
newDict.Add(kvp.Key, kvp.Value);
}
}
foreach(var dict in listOfDicts)
foreach (var kvp in dict)
{
if (newDict.ContainsKey(kvp.Key))
{
newDict[kvp.Key] += kvp.Value;
}
else
{
newDict.Add(kvp.Key, kvp.Value);
}
}
Pokey
Pokey2y ago
If newDict is Dictionary<string, string> yea I think that should work
Hercules
Hercules2y ago
That dosen't work, it basically copies the first Dictionary on the listOfDicts
Pokey
Pokey2y ago
let me see one second
Pokey
Pokey2y ago
Hercules @ C# | C# Online Compiler | .NET Fiddle
Hercules @ C# | Test your C# code online with .NET Fiddle code editor.
Pokey
Pokey2y ago
works fine
Hercules
Hercules2y ago
Huhh.. https://dotnetfiddle.net/cVXJef It does, i must've missed something. when i tried that. you see me newDict is of <string, long>
Hercules @ C# | C# Online Compiler | .NET Fiddle
Hercules @ C# | Test your C# code online with .NET Fiddle code editor.
Pokey
Pokey2y ago
Would have been useful if you said this at the start xD
Hercules
Hercules2y ago
That just means that the lowercase letters are numbers instead. The way we handle the types are the same, really. xD Maybeee not with the stringbuilder because i have to cast it to int64
Pokey
Pokey2y ago
Well no, actually, it changes my first answer a lot
Hercules
Hercules2y ago
How? Now im curious
Pokey
Pokey2y ago
instead of .First I would use .Sum This is one of those situations where I ask, what do you REALLY want to achieve here? Where are you coming from and where are you going to?
Hercules
Hercules2y ago
You know i have to try it out now. .Sum() @Pokey Works perfectly
Pokey
Pokey2y ago
Your example works? So
Hercules
Hercules2y ago
https://dotnetfiddle.net/gRV4lb this is your work really. 👏🏼
Hercules @ C# | C# Online Compiler | .NET Fiddle
Hercules @ C# | Test your C# code online with .NET Fiddle code editor.
Hercules
Hercules2y ago
I have two options to choose now. xD
dictionaries.SelectMany(dict => dict).ToLookup(pair => pair.Key, pair => pair.Value).ToDictionary(group => group.Key, group => group.Sum());

or

foreach(var dict in dictionaries){
foreach (var kvp in dict)
{
if (newDict.ContainsKey(kvp.Key))
{
newDict[kvp.Key] += kvp.Value;
}
else
{
newDict.Add(kvp.Key, kvp.Value);
}
}
}
dictionaries.SelectMany(dict => dict).ToLookup(pair => pair.Key, pair => pair.Value).ToDictionary(group => group.Key, group => group.Sum());

or

foreach(var dict in dictionaries){
foreach (var kvp in dict)
{
if (newDict.ContainsKey(kvp.Key))
{
newDict[kvp.Key] += kvp.Value;
}
else
{
newDict.Add(kvp.Key, kvp.Value);
}
}
}
Pokey
Pokey2y ago
Hercules @ C# | C# Online Compiler | .NET Fiddle
Hercules @ C# | Test your C# code online with .NET Fiddle code editor.
Pokey
Pokey2y ago
https://dotnetfiddle.net/EmciP6 Simplified a little further. Unnecessary .Select()
Hercules @ C# | C# Online Compiler | .NET Fiddle
Hercules @ C# | Test your C# code online with .NET Fiddle code editor.
Hercules
Hercules2y ago
Why not just add .Sum that gives same result.
Pokey
Pokey2y ago
where?
Hercules
Hercules2y ago
You changed lookup to groupby and added itm => itm.value inside sum; You should just leave it and have group.sum() that would result on same. Question here is whats faster groupby or lookupfor() -- and just thinking about it i think groupby key is faster xD nvm i like your solution
Pokey
Pokey2y ago
Pokey
Pokey2y ago
You meant this? Because this doesn't work because its a KVP not a long https://benchmarkdotnet.org/
Accord
Accord2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.