Reputation: 32416
I happen to use this kind of structure quite a lot:
Dictionary<string, List<string>> Foo = new Dictionary<string, List<string>>();
Which leads to this kind of code :
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());
}
Do you think it's worth writing a custom DictionaryOfList class which would handle this kind of things automatically?
Is there another way to lazily initialize those Lists?
Upvotes: 5
Views: 1864
Reputation: 2328
Why not just simplify a little:
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());
}
Upvotes: 0
Reputation: 192657
Don't forget the using directive.
This isn't directly responsive, but may be helpful anyway. A "using alias" for a generic collection type may make your code easier on the eyes.
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 for this hint.
Upvotes: 0
Reputation: 155892
Add a reference to System.Data.DataSetExtensions and you can use the Linq extensions:
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() );
I'm not sure I'd bother with another class, but a utility or extension method could make this simpler:
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") );
Upvotes: 1
Reputation: 1064244
A dictionary of a list... in .NET 3.5 that would be an ILookup<TKey,TValue>
. The default implementation (Lookup<TKey,TValue>
) is immutable, but I wrote an EditableLookup<TKey,TValue>
for MiscUtil. This will be a lot simpler to use - i.e.
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
}
Other than that, an extension method:
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");
}
Upvotes: 4
Reputation: 53974
You can write an extension method - GetValueOrCreateDefault() or something like that:
foreach (DataRow dr in ds.Tables[0].Rows)
{
Foo.GetValueOrCreateDefault( dr["Key"] ).Add( dr["Value"].ToString() )
}
Maybe you can even write an extension method for the whole initialisation?
Upvotes: 7
Reputation: 377
I think the following should do:
class DictionaryOfList : Dictionary<string, List<string>> {}
Upvotes: 2