score:2

Accepted answer

This is what you are looking to do:

  • Merge the two collections of dictionaries.
  • Group items by the "id" key-value.
  • For each group you have multiple dictionaries so use SelectMany to flatten and then GroupBy on the key. Now you can recreate the dictionaries - ToDictionary. Notice that you might have keys repeating themselves so that is why the nested GroupBy and for the value select the one you want. Here I just used FirstOrDefault

So:

var result = firstSourceData.Concat(secondSourceData)
                .GroupBy(item => item["id"])
                .Select(group => group.SelectMany(item => item)
                                      .GroupBy(item => item.Key)
                                      .ToDictionary(key => key.Key, 
                                                    value => value.FirstOrDefault().Value));

This is the result:

new Dictionary<string, object>
{
    ["id"] = 1,
    ["sales"] = 58,
    ["name"] = "some",
    ["age"] = 30
},
new Dictionary<string, object>
{
    ["id"] = 2,
    ["sales"] = 58,
    ["age"] = 30
}

For this test case:

var firstSourceData = new List<Dictionary<string, object>>
{
    new Dictionary<string, object>
    {
        ["id"] = 1,
        ["sales"] = 58,
        ["age"] = 30
    },
    new Dictionary<string, object>
    {
        ["id"] = 2,
        ["sales"] = 58,
        ["age"] = 30
    }
};

var secondSourceData = new List<Dictionary<string, object>>
{
    new Dictionary<string, object>
    {
        ["id"] = 1,
        ["name"] = "some",
        ["age"] = 30
    }
};

score:-1

You can do Union:

Dictionary<string,object> dict1 = new Dictionary<string, object>();
        dict1.Add("id", 1);
        dict1.Add("name", "Some");
        dict1.Add("age", 30);

        Dictionary<string, object> dict2 = new Dictionary<string, object>();
        dict2.Add("id", 1);
        dict2.Add("sales", 58);
        dict2.Add("age", 30);

        Dictionary<string, object> dict3 = new Dictionary<string, object>();
        dict3 = dict1.Union(dict2).ToDictionary(c => c.Key, c => c.Value);

Resulting values are:

[0] = {[id, 1]}
[1] = {[name, Some]}
[2] = {[age, 30]}
[3] = {[sales, 58]}

score:0

You can use Join like this

from dict1 in firstSourceData
join dict2 in secondSourceData
on dict1["id"] equals dict2["id"]
select dict1.Concat(                                      //concatenates 2 dictionaries together
          dict2.Where(kv => !dict1.ContainsKey(kv.Key))   //chooses non-repeating keys
       ).ToDictionary(kv => kv.Key, kv => kv.Value)       //gets a new dictionary from that

If the lengths of the sources are different join will only select these dictionaries, whose ids are in the first source. If you want to get all ids, regardless whether you have data from both sources, you can use DefaultIfEmpty

from dict1 in firstSourceData
join tempDict2 in secondSourceData
on dict1["id"] equals tempDict2["id"] into joined
from dict2 in joined.DefaultIfEmpty(new Dictionary<string, object>()) //make a new dictionary if there's none
select dict1.Concat(
          dict2.Where(kv => !dict1.ContainsKey(kv.Key))
       ).ToDictionary(kv => kv.Key, kv => kv.Value)

If you want dictionaries from both regardless of ids refer to this question.


Related Articles