C#合并2个词典

我正在开发一个面向.NET 3.5的C#应用​​程序。 在其中,我有2个类似的词典,其中包含我的应用程序中特定元素集的validation标准。 两个词典都有相同的签名。 第一个字典具有默认设置,第二个字典包含一些用户定义的设置。

var default_settings = new Dictionary(); var custom_settings = new Dictionary(); 

我想将2个词典合并为一个包含两个词典元素的词典。

我遇到的问题是两个字典都可能具有一些相同的键值。 我想要的基本规则是将两个字典组合在一起,如果default_settings中已存在custom_settings中的任何键,则custom_settings值将覆盖default_settings值。 我拥有的最佳解决方案只是一个foreach循环,检查密钥是否存在于另一个字典中,如果不存在,则添加它。

 foreach (var item in custom_settings) { if (default_settings.ContainsKey(item.Key)) default_settings[item.Key] = item.Value; else default_settings.Add(item.Key, item.Value); } 

我已经完成了一些基本的LINQ查询,但我仍在努力学习更高级的东西。 我已经看到了一些会合并2个词典的查询,但大多数都涉及将任何元素分组为重复键,或者只返回一个只有重复键的集合/是否有一个LINQ查询或表达式,它将模仿foreach循环的行为我在用?

两点:

  1. LINQ不适合执行副作用。 在这种情况下,您试图改变现有的集合而不是执行查询,所以我会回避纯粹的LINQ解决方案。
  2. 如果密钥不存在, 则通用字典的索引器上的setter已经具有添加键值对的效果,或者如果键不存在则覆盖该值。

设置属性值时,如果键位于“词典”中,则与该键关联的值将替换为指定的值。 如果该键不在字典中,则键和值将添加到字典中。

所以你的foreach循环基本上等同于:

 foreach (var item in custom_settings) { default_settings[item.Key] = item.Value; } 

现在已经非常简洁了,所以我不认为LINQ会帮助你这么多。

这是一个基于Ani答案的很好的扩展方法。

 public static class DictionaryExtensionMethods { public static void Merge(this Dictionary me, Dictionary merge) { foreach (var item in merge) { me[item.Key] = item.Value; } } } 

如果您要这么做,那么我建议为字典键编写一个相等比较器:

 private class KeyEqualityComparer : IEqualityComparer> { public bool Equals(KeyValuePair x, KeyValuePair y) { return x.Key.Equals(y.Key); } public int GetHashCode(KeyValuePair obj) { return obj.Key.GetHashCode(); } } 

然后,只要您需要合并字典,就可以执行以下操作

 var comparer = new KeyEqualityComparer(); dict1 = dict1.Union(dict2,comparer).ToDictionary(a => a.Key, b => b.Value); 

我认为我最初选择的答案仍然是这个特定情况的最佳答案,我发现自己在不久前的另一个类似的情况,我有2个IEnumerable<>对象,我想转换为字典并合并在一个类似的时尚,所以我想我会在这里添加解决方案,以帮助将来的人。 我找到了一种新方法,而不是将两者都转换为字典并使用所选答案中的方法。

我实际上在SE-CodeReview上发布了初始解决方案 ,并且实际上有一个建议进一步完善它。 这是我使用的最终代码:

 public Dictionary Merge(XElement element1, XElement element2) { IEnumerable firstFoos = GetXmlData(element1); // parse 1st set from XML IEnumerable secondFoos = GetXmlData(element2); // parse 2nd set from XML var result = firstFoos.Union(secondFoos).ToDictionary(k=>k.Name, v=>v); return result; } public class Foo { public String Name { get; } // other Properties and Methods // . // . // . public override Boolean Equals(Object obj) { if (obj is Foo) { return this.Name == ((Foo)obj).Name; } return false; } } 

关键是Foo必须重写Equals()来定义哪些Foo对象可以被认为是重复的,定义哪些对象重复的成员也应该是Dictionary<>键(在本例中为Name

如果你不能在Foo重写Equals() ,那么另一个选择是使用Concat()GroupBy()而不是Union()

 public Dictionary Merge(XElement element1, XElement element2) { IEnumerable firstFoos = GetXmlData(element1); // parse 1st set from XML IEnumerable secondFoos = GetXmlData(element2); // parse 2nd set from XML var result = firstFoos.Concat(secondFoos) .GroupBy(foo => foo.Name) .Select(grp => grp.First()) .ToDictionary(k=>k.Name, v=>v); return result; }