使用Enumerable.Union方法</tkey,>合并字典<tkey,tvalue =“”>

时间:2011-01-25 09:45:43

标签: c# dictionary merge union

我正在测试 UNION 方法以合并到字典(类型为Dictionary)。它适用于TValue类型是字符串或int甚至对象。但是如果TValue类型是一个集合(使用List和object []测试),则抛出异常:“ArgumentException:已经添加了具有相同键的项目。”

这是我的代码:

Dictionary<int,string> _dico1 = new Dictionary<int, string>()
{
    {0, "zero"},
    {1, "one"}
};

Dictionary<int,string> _dico2 = new Dictionary<int,string>()
{
    {1 , "one"},
    {2 , "two"},
    {3 , "three"},
    {4 , "four"},
    {5 , "five"},
    {6 , "six"}
};

Dictionary<int, List<string>> _dico3 = new Dictionary<int, List<string>>()
{
    {0, new List<string>{"zero"}},
    {1, new List<string>{"one"}}
};

Dictionary<int, List<string>> _dico4 = new Dictionary<int, List<string>>()
{
    {1, new List<string>{"one"}},
    {2, new List<string>{"two"}},
    {3, new List<string>{"three"}},
    {4, new List<string>{"four"}},
    {5, new List<string>{"five"}},
    {6, new List<string>{"six"}},
};

    // works fine
    var mergeDico = _dico1.Union(_dico2).ToDictionary(key => key.Key, value => value.Value);

    // throw an ArgumentException : An item with the same key has already been added
    var mergeDico2 = _dico3.Union(_dico4).ToDictionary(key => key.Key, value => value.Value);

为什么行为不一样?以及如何解决这个问题?

谢谢!

3 个答案:

答案 0 :(得分:7)

在第一种情况下,Union正在丢弃重复键,因为键/值对本身是相等的。在第二种情况下,他们不是,因为List<String>{"one"}不等于另一个List<string>{"one"}

我怀疑您希望Union来电IEqualityComparer使用{{1}},只会考虑字典中的键。

答案 1 :(得分:2)

您可以使用以下代码合并第二对词典:


var mergeDico2 = _dico3
    .Concat(_dico4)
    .GroupBy(_=> _.Key, _ => _.Value)
    .ToDictionary(
        group => group.Key,
        group => group.SelectMany(_ => _).ToList());

它将生成一个新字典,其中每个值都是连接两个字典值的列表的结果。如果您只需要列表的不同元素,则可以将ToDictionary调用更改为:


var mergeDico2 = _dico3
    .Concat(_dico4)
    .GroupBy(_=> _.Key, _ => _.Value)
    .ToDictionary(
        group => group.Key,
        group => group.SelectMany(_ => _).Distinct().ToList());

答案 2 :(得分:1)

正如Jon所说,我们需要实施IEqualityComparer来解决上述问题。以下是代码如何完成:

的IEqualityComparer:

public class MyEqualityComparer : IEqualityComparer<KeyValuePair<int,List<string>>>
{
    public bool Equals(KeyValuePair<int, List<string>> x, KeyValuePair<int, List<string>> y)
    {
        //Let's say we are comparing the keys only.
        return x.Key == y.Key;
    }

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

用法:

Dictionary<int, List<string>> _dico3 = new Dictionary<int, List<string>>()
    {
        {0, new List<string> {"zero"}},
        {1, new List<string> {"one"}}
    };

Dictionary<int, List<string>> _dico4 = new Dictionary<int, List<string>>()
    {
        {1, new List<string> {"one"}},
        {2, new List<string> {"two"}},
        {3, new List<string> {"three"}},
        {4, new List<string> {"four"}},
        {5, new List<string> {"five"}},
        {6, new List<string> {"six"}},
    };

Dictionary<int, List<string>> mergeDico2 = _dico3.Union(_dico4, new MyEqualityComparer())
    .ToDictionary(x => x.Key, x => x.Value);