C# 使用LINQ组合两个词典

C# 使用LINQ组合两个词典,c#,.net,linq,dictionary,C#,.net,Linq,Dictionary,我的问题已标记为可能与此问题重复: 我相信我的问题是不同的,因为我问的是如何以一种特殊的方式组合两个字典:我想要字典1中的所有项目加上字典2中不在字典1中(即键不存在)的所有项目 我有两本这样的字典: var d1 = new Dictionary<string,object>(); var d2 = new Dictionary<string,object>(); d1["a"] = 1; d1["b"] = 2; d1["c"] = 3; d2["a"] = 11

我的问题已标记为可能与此问题重复:

我相信我的问题是不同的,因为我问的是如何以一种特殊的方式组合两个字典:我想要字典1中的所有项目加上字典2中不在字典1中(即键不存在)的所有项目

我有两本这样的字典:

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;
但这给了我d1和d2的所有元素


看起来应该很明显,但我肯定遗漏了什么。

当您使用
时,除了默认情况下使用的
之外,它使用默认的相等比较器,该比较器对于
KeyValuePair
类型同时比较键和值。您可以采用这种方法:

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

您也可以使用自己的
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);
}
公共类MyComparer:IEqualityComparer{
公共布尔等于(键值对x、键值对y){
返回x.Key等于(y.Key);
}
public int GetHashCode(KeyValuePair obj){
返回obj.Key.GetHashCode();
}
}
...
字典d1=新字典();
d1.添加(“A”、“B”);
d1.添加(“C”、“D”);
字典d2=新字典();
d2.添加(“E”、“F”);
d2.添加(“A”、“D”);
d2.添加(“G”、“H”);
MyComparer comparer=新的MyComparer();
VarD3=d1.Concat(d2.除了(d1,比较器));
foreach(d3中的var a){
WriteLine(“{0}:{1}”,a.Key,a.Value);
}
Jon Skeet(像往常一样)有一个扩展方法,允许您执行以下操作:


这对我很有用。

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

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

我不知道这是否是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();
    }
}
class KeyValuePairComparer:IEqualityComparer
{
公共布尔等于(键值对x、键值对y)
{
返回x.Key等于(y.Key);
}
public int GetHashCode(KeyValuePair x)
{
返回x.GetHashCode();
}
}
然后:

var d3 = d1.Union(d2, new KeyValuePairComparer<string, object>());
var d3=d1.Union(d2,新的KeyValuePairComparer());
在您的示例中,输出将是(在C#interactive中测试):

>d1.Union(d2,新的KeyValuePairComparer())
联合迭代器{“a”,1},{“b”,2},{“c”,3},{“e”,12}
请注意区别:

> d2.Union(d1, new KeyValuePairComparer<string, object>())
UnionIterator { { "a", 11 }, { "e", 12 }, { "c", 13 }, { "b", 2 } }
>d2.Union(d1,新的KeyValuePairComparer())
联合迭代器{“a”,11},{“e”,12},{“c”,13},{“b”,2}

谢谢!这是一个很酷的方法,就像马克的一样。我知道我可以使用IEqualityComparer,但我想知道是否有更简单的方法。通常对于键比较之类的快速操作,LINQ可能是最好的方法,但如果您需要更复杂的东西(并且需要重用它),
IEqualityComparer
可能会更好,特别是如果作为一个扩展方法实现的话。那真的很酷!我现在可能不会这么做,但稍后会把它归档。有很多Linq扩展。在这种情况下,我会使用ExceptBy来思考:这个问题的可能重复并不是那个问题的重复。这个问题是询问如何组合两个字典,d1和d2,以便生成的字典包含d1中的所有项以及d2中尚未包含在d1中的所有项。另一个问题是问,答案解释了如何在没有任何额外条件的情况下合并两本词典。
var d3 = d1.Union(d2, new KeyValuePairComparer<string, object>());
> 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 } }