1

I want to find a union of two dictionaries, that may contain the same keys, but different values. If key exists in both dictionaries, then I want to merge the values (if they differ) into list. If key exists in only one dictionary, then I want to create a List and add that item to it.

So, for example:

var dict1 = new Dictionary<int, string>();
var dict2 = new Dictionary<int, string>();

dict1.Add(1, "a");
dict2.Add(1, "b");
dict1.Add(2, "c");

var resultDict = Combine(dict1, dict2);

Result dictionary will be the type of Dictionary<int, List>, and will contain { 1: ["a", "b"], 2: ["c"]}.

The simplest solution I can think of, is to traverse union of keys and add empty lists, then traverse both dictionaries and add all values to list for given keys.

Is there any good, functional solution to combine these two Dictionaries?

Szymon Żak
  • 491
  • 1
  • 3
  • 17
  • 1
    Have you checked this ? [Similar topic](https://stackoverflow.com/questions/294138/merging-dictionaries-in-c-sharp) – startresse Mar 15 '21 at 09:45
  • 2
    @startresse: related but not duplicate since those question wants to create a merged `Dictionary` whereas this question wants a `Dictionary>` and no answer there shows it. – Tim Schmelter Mar 15 '21 at 11:15

1 Answers1

1

What if i wanted to combine more than two dictionaries?

You could use following method which also shows how to optionally pass a custom comparer for the key(for example if the key was a string which you want to compare in a case insensitive way):

public static Dictionary<TKey, List<TValue>> Combine<TKey, TValue>(
    IEqualityComparer<TKey> comparer = null,
    params IDictionary<TKey, TValue>[] dictionaries)
{
    if (comparer == null) comparer = EqualityComparer<TKey>.Default;
    Dictionary<TKey, List<TValue>> result = new Dictionary<TKey, List<TValue>>(comparer);
    IEnumerable<TKey> allKeys = dictionaries.SelectMany(dict => dict.Keys).Distinct(comparer);
    foreach (TKey key in allKeys)
    {
        List<TValue> list = new List<TValue>();
        foreach (IDictionary<TKey, TValue> dict in dictionaries)
        {
            if (dict.TryGetValue(key, out TValue value)) list.Add(value);
        }
        result.Add(key, list);
    }

    return result;
}

Pass null for the comparer if you want to use the default comparer:

Dictionary<int, List<string>> resultDict = Combine(null, dict1, dict2, dict3);
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939