2011-02-04 89 views
19

我的问题已被标记为这个问题的一个可能重复:How to combine two dictionaries without looping?结合两个词典与LINQ

我相信我的问题是不同的,因为我是问如何将两个字典以特定方式结合起来:我想所有项目从Dictionary1加上Dictionary1中所有不在Dictionary1中的项目(即密钥不存在)。

我有两本词典是这样的:

var d1 = new Dictionary<string,object>(); 
var d2 = new Dictionary<string,object>(); 

d1["a"] = 1; 
d1["b"] = 2; 
d1["c"] = 3; 

d2["a"] = 11; 
d2["e"] = 12; 
d2["c"] = 13; 

我想将它们合并成一个新的词典(在技术上,它并不一定是一个字典,它可能只是的KeyValuePairs序列)等输出包含来自d1的所有KeyValuePairs以及仅来自d2的KeyValuePairs,其密钥未出现在d1中。

概念:

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

但是,这是给我所有的D1和D2元素。

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

+0

的可能的复制[如何添加2个词典内容,而不循环在C#](http://stackoverflow.com/questions/712927/how-to-add-2-dicti onary-contents-without-in-c-sharp) – 2016-04-28 05:01:16

+1

这个问题不是这个问题的重复。这个问题是问如何组合两个字典,d1和d2,使得生成的字典包含d1中的所有项目以及来自d2的所有项目,这些项目不在d1中。另一个问题是要求,而且答案解释了如何在没有任何额外条件的情况下合并两本字典。 – wageoghe 2016-04-28 17:58:46

回答

33

默认情况下使用Except时,它使用默认的相等比较器,该比较器对KeyValuePair类型比较键和值。您可以改为:

var d3 = d1.Concat(d2.Where(kvp => !d1.ContainsKey(kvp.Key))); 
1

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

public class MyComparer : IEqualityComparer<KeyValuePair<string,string>> { 
    public bool Equals(KeyValuePair<string, string> x, KeyValuePair<string, string> y) { 
     return x.Key.Equals(y.Key); 
    } 

    public int GetHashCode(KeyValuePair<string, string> obj) { 
     return obj.Key.GetHashCode(); 
    } 
} 

... 

Dictionary<string, string> d1 = new Dictionary<string, string>(); 
d1.Add("A", "B"); 
d1.Add("C", "D"); 

Dictionary<string, string> d2 = new Dictionary<string, string>(); 
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); 
} 
+0

谢谢!这是一个非常酷的方法,以及马克的。我看到我可以使用IEqualityComparer,但我想知道是否有更简单的方法。 – wageoghe 2011-02-04 23:21:49

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

这是为我工作。

1

使用另一种解决方案你自己IEqualityComparer像@bitxwise和@DaveShaw的答案,但没有使用Except()这使得它有点简单:

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

好吧,我不知道这是否是一个新功能在LINQ,但是这正是.Union()做:

var d3 = d1.Union(d2); 

当然用字典,你得给一个自定义相等比较器只匹配键:

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

然后:

var d3 = d1.Union(d2, new KeyValuePairComparer<string, object>()); 

你的榜样,输出会(在C#交互测试):

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

注意区别:

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