【问题标题】:How to Join two dictionary collections linq query如何加入两个字典集合linq查询
【发布时间】:2017-08-15 19:45:10
【问题描述】:

我的第一个数据收集是这样的:

IEnumerable<Dictionary<string, object>> firstSourceData;

物品是这样的:

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

我的第二个数据是另一个字典集合:

IEnumerable<Dictionary<string, object>> secondSourceData;

物品是这样的:

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

这两个数据来自不同的来源,我将创建一个不包含重复值的字典集合。只有 ID 键是字典的标准,其他属性可能会更改。

IEnumerable<Dictionary<string, object>> joined;

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

如何使用 LINQ lambda 表达式做到这一点? (如果源长度不同有什么问题吗)

【问题讨论】:

  • 所以你想通过 id 加入?
  • 是的,按 id 加入。
  • @Bookmaster:每个字典都包含 id-key?
  • 是的包含 id 键,它是标准的。
  • 加入的字典集合不会包含重复项。

标签: c# linq


【解决方案1】:

这就是你想要做的:

  • 合并两个字典集合。
  • 按“id”键值对项目进行分组。
  • 对于每个组,您都有多个字典,因此请使用SelectMany 进行展平,然后在键上使用GroupBy。现在您可以重新创建字典 - ToDictionary。请注意,您可能有重复的键,这就是为什么嵌套 GroupBy 并为值选择您想要的。这里我只是用了FirstOrDefault

所以:

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));

这是结果:

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

对于这个测试用例:

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
    }
};

【讨论】:

  • .ToDictionary(key =&gt; key.Key, value =&gt; value.FirstOrDefault().Value) 为我工作。谢谢
  • @bookmarker - ops true :) 否则值为KeyValuePair&lt;string,object&gt;。已更正
  • 我们可以在不使用 id 键的情况下执行此操作吗?你能加入所有,没有重复吗?所以所有属性都会插入到新字典中。
  • @bookmarker - 你想要的输出是什么?还是字典合集?
  • 是字典的集合。加入字典但不重复。
【解决方案2】:

你可以像这样使用Join

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

如果源的长度不同,join 将只选择这些字典,其ids 在第一个源中。如果你想获取所有ids,不管你是否有两个来源的数据,都可以使用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)

如果无论ids 是什么都想要字典,请参阅this 问题。

【讨论】:

  • Zip 不是按 ID 加入,而是按索引加入。 OP 想要一个扁平化版本,其中集合包含每个 id 的字典,以及属于该 id 并在所有字典中找到的所有收集的属性。
  • 好吧,op 没有提到过类似的事情 :)
  • 但是您做出了从未提及的假设,OP 刚刚说过他希望每个 id 都有一个字典,其中还包含属于该 ID 的所有其他“属性”(键值对)并且是从两个序列中的所有字典中收集。唯一静态的是每个字典都包含 id-key。
  • 如果一个来源包含的 id 不在另一个来源中怎么办?这种方法将它们排除在外。
【解决方案3】:

你可以做联合:

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);

结果值为:

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

【讨论】:

  • 不是Dictionary&lt;string, object&gt;它的集合IEnumerabl&lt;Dictionary&lt;string, object&gt;&gt;
猜你喜欢
  • 2018-12-09
  • 1970-01-01
  • 1970-01-01
  • 2021-11-22
  • 2013-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多