2009-05-15 9 views
5

は、私は、この種の構造を使用するために起こるかなり多く:C#でリストの辞書を初期化する際の苦労を緩和するにはどうすればよいですか?

この種のコードにつながる
Dictionary<string, List<string>> Foo = new Dictionary<string, List<string>>(); 

foreach (DataRow dr in ds.Tables[0].Rows) 
{ 
    List<string> bar; 
    if (!Foo.TryGetValue(dr["Key"].ToString(), out desks)) 
    { 
     bar= new List<string>(); 
     Foo.Add(dr["Key"].ToString(), bar); 
    } 
    bar.Add(dr["Value"].ToString()); 
} 

あなたはそれがこれを処理することになるカスタムDictionaryOfListクラスを書く価値があると思いますか物事の種類は自動的に?

これらのリストを遅延して初期化する別の方法はありますか?

+0

はちょっと何の事あなたがのために、この構造が有用見つけるのですか?かなり新しいプログラマであり、私はまだそれほど辞書構造を使用していないと思う! – RYFN

+0

フレームワークのバージョン情報が役に立ちます、LINQはこれをもっときれいにすることができます – AnthonyWJones

+0

@Anthony:確かに。言及する編集されたタグ.net3.5 – Brann

答えて

7

あなたは、拡張メソッドを書くことができます - GetValueOrCreateDefault()、またはそのような何か:

foreach (DataRow dr in ds.Tables[0].Rows) 
{ 
    Foo.GetValueOrCreateDefault(dr["Key"]).Add(dr["Value"].ToString()) 
} 

はたぶん、あなたも全体の初期化のための拡張メソッドを書くことができますか?

+0

ニースのソリューションですが、さらに進んで拡張メソッド辞書を作成します。AddPair(TKey、TValue)。誰かがコードを見なければならない場合、これは読みやすく、理解しやすくなります。 –

2

私は次のようにすればいいと思う:私はもっときちんと読むべき

class DictionaryOfList : Dictionary<string, List<string>> {} 
  • 編集。これは質問に答えません。 Tanasciusはそれを解決するためにきちんとした方法を提供しています。
+0

ありがとう、それは便利です! – Nick

4

リストの辞書... .NET 3.5では、ILookup<TKey,TValue>となります。デフォルト実装(Lookup<TKey,TValue>)は不変ですが、私はMiscUtilのためにEditableLookup<TKey,TValue>と書いています。これは使用することがずっと簡単になります - それ以外すなわち

var data = new EditableLookup<string, int>(); 
data.Add("abc",123); 
data.Add("def",456); 
data.Add("abc",789); 

foreach(int i in data["abc"]) { 
    Console.WriteLine(i); // 123 & 789 
} 

、拡張メソッド:

public static void Add<TKey, TList, TValue>(
    this IDictionary<TKey, TList> lookup, 
    TKey key, TValue value) 
    where TList : class, ICollection<TValue>, new() 
{ 
    TList list; 
    if (!lookup.TryGetValue(key, out list)) 
    { 
     lookup.Add(key, list = new TList()); 
    } 
    list.Add(value); 
} 

static void Main() { 
    var data = new Dictionary<string, List<string>>(); 
    data.Add("abc", "def"); 
} 
+0

ニース!私は<4つの拡張方法です。 –

+0

本当にうれしいですが、私はまだ保守性とそれを使って行うことができる曖昧なものについては本当に確信していません。たとえば、拡張メソッドを使用してインタフェースのデフォルトの実装を実装します。 しかし、この場合は非常に便利です! – Kevin

1

がSystem.Data.DataSetExtensionsへの参照を追加して、LINQの拡張機能を使用することができます

var dictOfLst = ds.Tables[0].Rows. 
    //group by the key field 
    GroupBy(dr => dr.Field<string>("key")). 
    ToDictionary(
     grp => grp.Key, 
     //convert the collection of rows into values 
     grp => grp.Select(dr => dr.Field<string>("value")).ToList()); 

私は別のクラスを気にしたいわからないんだけど、ユーティリティまたは拡張メソッドが、これは簡単にすることができます:

public static Dictionary<TKey, List<TValue>> ToGroupedDictionary<TKey, List<TValue>>(
    this DataTable input, 
    Func<TKey, DataRow> keyConverter, 
    Func<TValue, DataRow> valueConverter) 
{ 
    return input.Rows. 
     //group by the key field 
     GroupBy(keyConverter). 
     ToDictionary(
      grp => grp.Key, 
      //convert the collection of rows into values 
      grp => grp.Select(valueConverter).ToList()); 
} 

//now you have a simpler syntax 
var dictOfLst = ds.Tables[0].ToGroupedDictionary(
    dr => dr.Field<string>("key"), 
    dr => dr.Field<string>("value")); 
+1

ToLookupがありますか? –

0

the using directiveを忘れないでください。

これは直接的な反応ではありませんが、とにかく役に立ちます。一般的なコレクション型に "エイリアスを使用する"と指定すると、コードが目に見えやすくなります。

using StoreBox = System.Collections.Generic.Dictionary<string, System.Collections.Generic.List<string>>; 
using ListOfStrings = System.Collections.Generic.List<string>; 
class Program 
{ 
    static void Main(string[] args) 
    { 
     var b = new StoreBox(); 
     b.Add("Red", new ListOfStrings {"Rosso", "red" }); 
     b.Add("Green", new ListOfStrings {"Verde", "green" }); 
    } 
} 

Credit to SOこのヒントについては、

0

はなぜほんの少しの簡素化:

foreach (DataRow dr in ds.Tables[0].Rows) 
{ 
    string key = dr["Key"].ToString(); 
    if (!Foo.ContainsKey(key)) Foo.Add(key, new List<string>()); 
    Foo[key].Add(dr["Value"].ToString()); 
} 
+0

それをしない理由は、複雑さがO(n)ではなくO(2n)になるということです。もちろん、ほとんどの場合、それはおそらく問題ではないでしょう。 – Brann

関連する問題