在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
。 从这些组中,我们可以使用>
SelectMany
的Select
转换将所有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
。 我假设它是一个为你选择的TKey
和T
实现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);