将两个词典与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());