Словарь слиянияс методом Enumerable.Union - PullRequest
7 голосов
/ 25 января 2011

Я тестирую метод UNION для объединения со словарями (типа Словарь). Он отлично работает с типом TValue - string, int или даже object. Но если тип 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 ]

7 голосов
/ 25 января 2011

В первом случае Union отбрасывает дублирующиеся ключи, потому что сами пары ключ / значение равны.Во втором случае это не так, потому что List<String>{"one"} не равен другому List<string>{"one"}.

Я подозреваю, что вы хотите, чтобы ваш звонок Union использовал IEqualityComparer, который учитывает толькоключи в словаре.

2 голосов
/ 25 января 2011

Вы можете объединить вторую пару словарей с кодом следующим образом:


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());

1 голос
/ 02 августа 2012

Как уже упоминал Джон, нам нужно реализовать 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...