2011-01-25 6 views
7

辞書(Dictionary型)にマージするUNIONメソッドをテストしています。 TValueの型は文字列またはintまたはオブジェクトでも正常に動作します。しかし、TValueの型がコレクション(Listとobject []でテスト済み)の場合、例外がスローされます。"ArgumentException:同じキーを持つ項目が既に追加されています。"ここでEnumer Dictionary <TKey、TValue>とEnumerable.Unionメソッド

は私のコードです:

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

動作は同じではありませんなぜ?そしてこの問題を解決するには?

ありがとうございました!

答えて

7

最初のケースでは、キーと値のペア自体が等しいため、連合は重複キーを破棄しています。 2番目のケースでは、List<String>{"one"}が別のList<string>{"one"}と等しくないため、そうではありません。

Unionコールには、辞書内のキーのみを考慮したIEqualityComparerを使用すると思われます。

+0

だから、最初のケースでは、それは動作しますか不変型(文字列)であり、TValueが参照型なので失敗します。 – Florian

+5

@Florian:それは、不変性に直接起因するものではありません。それは、関係する型がバリュー・イコール・セマンティクスを持っているかどうかによるものです。あなたはまだそれをしない不変の型を持つことができます。 –

2

次のようなコードで辞書の第二の対をマージすることができます:それは、それぞれの値は、両方の辞書の値からリストを連結した結果である新しい辞書を生成します

 

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

。ジョンは、我々は上記の問題を解決するためにIEqualityComparerを実装する必要があることをすでに述べたように

 

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

:あなたがリストの唯一の明確な要素が必要な場合は、このいずれかのToDictionaryの呼び出しを変更することができます。ここでは、それがどのように行うことができるかのコードは次のとおりです。

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

使用法:TValue型は値型(int型)であるため、

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); 
関連する問題