如何缓解在C#中初始化列表字典的痛苦?

时间:2009-05-15 09:44:07

标签: c# .net .net-3.5 collections

我碰巧使用了这种结构:

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类是否值得自动处理这类事情?

还有另一种懒惰地初始化这些列表的方法吗?

6 个答案:

答案 0 :(得分:7)

你可以写一个扩展方法 - GetValueOrCreateDefault()或类似的东西:

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

也许你甚至可以为整个初始化编写扩展方法?

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

答案 2 :(得分:2)

我认为以下情况应该:

class DictionaryOfList : Dictionary<string, List<string>> {} 
  • 编辑我应该更正确地阅读。这不回答这个问题。 Tanascius提供了一种解决问题的简洁方法。

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

答案 4 :(得分: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这个提示。

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