Merging Dictionaries in C#

Merging dictionaries in C#

This partly depends on what you want to happen if you run into duplicates. For instance, you could do:

var result = dictionaries.SelectMany(dict => dict)
.ToDictionary(pair => pair.Key, pair => pair.Value);

That will throw an exception if you get any duplicate keys.

EDIT: If you use ToLookup then you'll get a lookup which can have multiple values per key. You could then convert that to a dictionary:

var result = dictionaries.SelectMany(dict => dict)
.ToLookup(pair => pair.Key, pair => pair.Value)
.ToDictionary(group => group.Key, group => group.First());

It's a bit ugly - and inefficient - but it's the quickest way to do it in terms of code. (I haven't tested it, admittedly.)

You could write your own ToDictionary2 extension method of course (with a better name, but I don't have time to think of one now) - it's not terribly hard to do, just overwriting (or ignoring) duplicate keys. The important bit (to my mind) is using SelectMany, and realising that a dictionary supports iteration over its key/value pairs.

Merge two dictionaries in C#

You merge them like this:

var d1 = new Dictionary<int, string>() { [1] = "one" };
var d2 = new Dictionary<int, string>() { [1] = "un", [2] = "deux" };

var merged = d1.Concat(d2)
.ToLookup(x => x.Key, x => x.Value)
.ToDictionary(x => x.Key, g => g.First());

Combine multiple dictionaries into a single dictionary


var d1 = new Dictionary<string, int>();
var d2 = new Dictionary<string, int>();
var d3 = new Dictionary<string, int>();

var result = d1.Union(d2).Union(d3).ToDictionary (k => k.Key, v => v.Value);

EDIT

To ensure no duplicate keys use:

var result = d1.Concat(d2).Concat(d3).GroupBy(d => d.Key)
.ToDictionary (d => d.Key, d => d.First().Value);

c# merging multiple dictionaries into one

Since dictionaries implement IEnumerable<KeyValuePair<TKey, TValue>>, you can simply write:

var result = dict1
.Concat(dict2)
.Concat(dict3)
.Concat(dict4)
.Concat(dict5)
.ToDictionary(e => e.Key, e => e.Value);

This assumes that there are no duplicate keys.

If there are duplicate keys, you could get the first value for each key

result = dict1
.Concat(dict2)
.Concat(dict3)
.Concat(dict4)
.Concat(dict5)
.GroupBy(e => e.Key)
.ToDictionary(g => g.Key, g => g.First().Value);

Other variants are conceivable, like keeping the maximum/minimum value etc.

If there are duplicate keys with different values, you could also create a dictionary of value lists

Dictionary<TKey, List<TValue>> result = dict1
.Concat(dict2)
.Concat(dict3)
.Concat(dict4)
.Concat(dict5)
.GroupBy(e => e.Key, e => e.Value)
.ToDictionary(g => g.Key, v => v.ToList());

Instead of creating a List<T> of values, you could insert them into a HashSet<T> to only keep unique values.

If the values are always the same for duplicate keys then simply use Union instead of Concat:

var result = dict1
.Union(dict2)
.Union(dict3)
.Union(dict4)
.Union(dict5)
.ToDictionary(e => e.Key, e => e.Value);

Union produces the set union of two sequences. Concat concatenates two sequences.

Finally, you can combine the two preceding approaches and discard equal key/value pairs, but keep a list of different values per key:

Dictionary<TKey, List<TValue>> result = dict1
.Union(dict2)
.Union(dict3)
.Union(dict4)
.Union(dict5)
.GroupBy(e => e.Key, e => e.Value)
.ToDictionary(g => g.Key, v => v.ToList());

These examples show that it is important to know exactly how the input data is shaped (unique/non-unique keys and key-value-pairs) and precisely what kind of result you expect.


A different approach would be to let your different methods return lists or enumerations instead of dictionaries and merge these collections into a dictionary at the end. This would be more performing.

Concatenate two Dictionaries

I think you defined your GroupNames as Dictionary<string,string>, so you need to add ToDictionary like this:

GroupNames = GroupNames.Concat(AddedGroupNames)
.ToDictionary(x=>x.Key,x=>x.Value);

Note that 2 original dictionaries would have different keys, otherwise we need some rule to merge them correctly.

Combining values of two dictionaries in C# with distinct keys

Simplest solution would be with Dictionary.Keys

var D1 = new Dictionary<int,string>(){{2,"a"}, {3,"b"},{4,"c"}};
var D2 = new Dictionary<int,string>(){{1,"e"},{2,"f"}, {4,"h"},{5,"i"}};

var keys = D1.Keys.Union(D2.Keys).OrderBy(key => key);
var test = keys.Select(key => new {Key = key, Value= new string[] {D1.ContainsKey(key) ? D1[key] : "", D2.ContainsKey(key) ? D2[key] : ""} });
Console.WriteLine(test);

Interactive: https://rextester.com/UXQ51844

Alternatively, you could do something similar to this: LINQ - Full Outer Join

C# Linq Merging Dictionaries

This concatenates the two dictionaries, as you said.

a.Concat(b)

Then, from the concatenated list, we group the values based on the dictionary keys

.GroupBy(p => p.Key)

Finally, we export the data as a dictionary, using the existing key as the key in the exported dictionary

.ToDictionary(g => g.Key, 

and the last value that matches that key as the value. The other values in the group are ignored.

g => g.Last().Value);

The expressions used in the methods, e.g. p => p.Key, in this case roughly mean "Of the object type in the list before, use it using the variable name p, and then get the value from the expression after the =>"

Hope this helps you to understand what it's doing. It took me a while to get my head round linq when I first started with it too.

C# Merging 2 dictionaries

Two points:

  1. LINQ isn't great for executing side effects. In this case, you're attempting to mutate an existing collection rather than execute a query, so I would shy away from a pure LINQ solution.
  2. The setter on the generic dictionary's indexer already has the effect of adding the key-value pair if the key doesn't exist, or overwriting the value if it does.

When you set the property value, if
the key is in the Dictionary, the value associated with
that key is replaced by the assigned
value. If the key is not in the
Dictionary, the key and
value are added to the dictionary.

So your foreach loop is essentially equivalent to:

foreach (var item in custom_settings)
{
default_settings[item.Key] = item.Value;
}

Now that's pretty terse already, so I don't think LINQ is going to help you all that much.

How to merge two dictionaries but on duplicate keys combine the values in C#?

You could first merge your dictionaries in a IEnumerable<KeyValuePair<string, List<int>>> by combining them with Concat. We do this because some keys may not exist in both dictionaries, and we want them included in the final merged result.

We can then group the keys with ToLookup, then create a final merged Dictionary<string, List<int>> with ToDictionary, ensuring that the inner grouped lists are flattened with SelectMany.

var dictA = new Dictionary<string, List<int>>
{
{ "wow", new List<int>{0,0,0} },
{ "key", new List<int>{1,2,3} }
};

var dictB = new Dictionary<string, List<int>>
{
{ "querty", new List<int>{4,0,4} },
{ "key", new List<int>{4,5,6} }
};

var merged = dictA
.Concat(dictB)
.ToLookup(kvp => kvp.Key, kvp => kvp.Value)
.ToDictionary(group => group.Key, group => group.SelectMany(x => x).ToList());

foreach (var kvp in merged)
{
Console.WriteLine($"{kvp.Key} -> {"{ " + string.Join(", ", kvp.Value) + " }"}");
}

Output:

wow -> { 0, 0, 0 }
key -> { 1, 2, 3, 4, 5, 6 }
querty -> { 4, 0, 4 }

How to merge two dictionaries in C# with duplicates

If you want a LINQ approach, try this:

Dictionary<string, string[]> firstDic = new Dictionary<string, string[]>  
{
{"apple", new [] {"red"}},
{"orange", new [] {"orange"}}
};

Dictionary<string, string[]> secondDic = new Dictionary<string, string[]>
{
{"apple", new [] {"green"}},
{"banana", new [] {"yellow"}}
};

Dictionary<string, string[]> resultDic = firstDic.Union(secondDic)
.GroupBy(o => o.Key)
.ToDictionary(o => o.Key, o => o.SelectMany(kvp => kvp.Value).ToArray());

For the sample data, you'll get a Dictionary with 3 KeyValuePairs, and the item with a Key of "apple" will have an Array with "red" and "green" for the value.



Related Topics



Leave a reply



Submit