将两个词典与LINQ结合使用

我的问题被标记为这个问题的可能重复: 如何在没有循环的情况下组合两个词典?

我相信我的问题是不同的,因为我问的是如何以特定的方式组合两个词典:我希望Dictionary1中的所有项目加上Dictionary2中不存在的所有项目(即密钥不存在)。

我有两个这样的词典:

var d1 = new Dictionary(); var d2 = new Dictionary(); d1["a"] = 1; d1["b"] = 2; d1["c"] = 3; d2["a"] = 11; d2["e"] = 12; d2["c"] = 13; 

我想将它们组合成一个新的Dictionary(技术上,它不必是一个字典,它可能只是一个KeyValuePairs序列),这样输出包含来自d1的所有KeyValuePairs和只有来自d2的KeyValuePairs的Key没有出现在d1

概念:

 var d3 = d1.Concat(d2.Except(d1)) 

但这给了我d1和d2的所有元素。

似乎它应该是显而易见的,但我必须遗漏一些东西。

当您默认使用Except ,它使用默认的相等比较器, KeyValuePair类型比较键和值。 你可以这样做:

 var d3 = d1.Concat(d2.Where(kvp => !d1.ContainsKey(kvp.Key))); 
 var d3 = d1.Concat(d2.Where(kvp => ! d1.ContainsKey(kvp.Key))) .ToDictionary(x => x.Key, x => x.Value); 

这对我有用。

Jon Skeet(像往常一样)有一个扩展方法允许你这样做: 我可以指定我的显式类型比较器内联吗?

好吧,我不知道它是否是LinQ中的新function,但这正是.Union()所做的:

 var d3 = d1.Union(d2); 

当然,对于字典,您必须提供自定义相等比较器以仅匹配键:

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

然后 :

 var d3 = d1.Union(d2, new KeyValuePairComparer()); 

在您的示例中,输出将是(在C#交互式测试中):

 > d1.Union(d2, new KeyValuePairComparer()) UnionIterator { { "a", 1 }, { "b", 2 }, { "c", 3 }, { "e", 12 } } 

注意区别:

 > d2.Union(d1, new KeyValuePairComparer()) UnionIterator { { "a", 11 }, { "e", 12 }, { "c", 13 }, { "b", 2 } } 

您也可以使用自己的IEqualityComparer 。 示例如下:

 public class MyComparer : IEqualityComparer> { public bool Equals(KeyValuePair x, KeyValuePair y) { return x.Key.Equals(y.Key); } public int GetHashCode(KeyValuePair obj) { return obj.Key.GetHashCode(); } } ... Dictionary d1 = new Dictionary(); d1.Add("A", "B"); d1.Add("C", "D"); Dictionary d2 = new Dictionary(); d2.Add("E", "F"); d2.Add("A", "D"); d2.Add("G", "H"); MyComparer comparer = new MyComparer(); var d3 = d1.Concat(d2.Except(d1, comparer)); foreach (var a in d3) { Console.WriteLine("{0}: {1}", a.Key, a.Value); } 

使用你自己的IEqualityComparer另一个解决方案,如@bitxwise和@DaveShaw的答案,但不使用Except() ,这使得它更简单:

 var d3 = d1.Concat(d2).Distinct(new MyComparer());