将两个词典与LINQ结合使用

时间:2011-02-04 23:03:37

标签: c# .net linq dictionary

我的问题已被标记为此问题的可能重复:How to combine two dictionaries without looping?

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

我有两个这样的词典:

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;

我想将它们组合成一个新的Dictionary(从技术上讲,它不必是一个字典,它可能只是一个KeyValuePairs的序列),以便输出包含所有KeyValuePairs }来自d1,只有来自d2的KeyValuePairs,其Key未出现在d1中。

概念:

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

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

似乎很明显,但我必须遗漏一些东西。

6 个答案:

答案 0 :(得分:36)

默认使用Except时,它使用默认的相等比较器,KeyValuePair类型比较键和值。你可以采用这种方法:

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

答案 1 :(得分:7)

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

这对我有用。

答案 2 :(得分:2)

Jon Skeet(像往常一样)有一个扩展方法,可以让你这样做:Can I specify my explicit type comparator inline?

答案 3 :(得分: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 } }

答案 4 :(得分: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);
}

答案 5 :(得分:1)

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

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