在C#中合并包含List的字典

这与这个问题有关 ,关于如何在C#中合并两个词典。 提出了一个优雅的Linq解决方案,很酷。

但是,该问题与Dictionary,而我有一个字典,其值为List.

我正在寻找一个合并Dictionary<Object1, List>,的解决方案Dictionary<Object1, List>,具有以下要求:

  • 如果Dictionary1包含与Dictionary2相同的键,则应组合它们的List列表。 您最终会得到一个带有共享密钥的新键值对,以及来自两个词典的组合列表。
  • 如果Dictionary1包含Dictionary2没有的键,则Dictionary1中的List列表应该成为值,反之亦然。

这在Linq中可能是不可能的,或者可能值得用for循环等来写出来,但是有一个优雅的解决方案会很好。

我建议你创建自己的扩展方法。 它将更有效,更容易修改。

 public static void MergeDictionaries(this IDictionary> dict1, IDictionary> dict2) { foreach (var kvp2 in dict2) { // If the dictionary already contains the key then merge them if (dict1.ContainsKey(kvp2.Key)) { dict1[kvp2.Key].AddRange(kvp2.Value); continue; } dict1.Add(kvp2); } } 

困难在于处理关键冲突的合并。

如果我们首先使用SelectMany平所有输入词典,我们可以按键将元素组合在一起。

 var result = dictionaries .SelectMany(dict => dict) .GroupBy(kvp => kvp.Key) 

结果集包含组,其中每个组的键是原始字典中的键,组的内容是具有相同键的列表的IEnumerable> 。 从这些组中,我们可以使用SelectManySelect转换将所有List合并到单个IEnumerable

 var result = dictionaries .SelectMany(dict => dict) .GroupBy(kvp => kvp.Key) .Select(grp => new { Key = grp.Key, Items = grp.SelectMany(list => list)}) 

然后我们可以使用ToDictionary转换从中获取字典,将IEnumerable转换回List

 var result = dictionaries .SelectMany(dict => dict) .GroupBy(kvp => kvp.Key) .Select(grp => new { Key = grp.Key, Items = grp.SelectMany(list => list)}) .ToDictionary(kip => kip.Key, kip => new List(kip.Items)); 

更新以回应评论

您可以随意填充dictionaries 。 我假设它是一个为你选择的TKeyT实现IEnumerable>>的类型。

最简单的方法是使用List ,如下所示:

 List>> dictionaries = new List>>(); dictionaries.Add(dictionary1); // Your variable dictionaries.Add(dictionary2); // Your variable // Add any other dictionaries here. // Code as above! 

您只需将解决方案中的项目合并部分更改为上一个问题。 对于对象,我们有这个:

 .ToDictionary(group => group.Key, group => group.First()) 

即对于重复的项目,只需采取第一个。

但我们可以用这个:

 .ToDictionary(group => group.Key, group => group.SelectMany(list => list).ToList()); 

连接列表。

所以,最终的表达方式是

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

如果需要一些额外的列表合并逻辑(例如,只合并不同的项),您可以尝试使用不同的合并表达式

我会第一个承认这不是那么漂亮,但这对我有用。

 var d1 = new Dictionary>(); var d2 = new Dictionary>(); d1["test"] = new List() { "Stockholm", "Motala" }; d1["more"] = new List() { "numerous", "populous", "bigger", "plentiful" }; d2["test"] = new List() { "Washington", "Charlottesville" }; d2["less"] = new List() { "insufficient", "small", "imperceptible" }; var intersect = (from key in d1.Keys.Intersect(d2.Keys) select new { Key = key, Value = new List(d1[key].Concat(d2[key])) }).ToDictionary(d => d.Key, d => d.Value); var merged = d1.Concat(d2).Where(d => !intersect.Keys.Contains(d.Key)).Concat(intersect).ToDictionary(d => d.Key, d => d.Value);