将DataTable转换为Dictionary <string,stringbuilder> </string,stringbuilder>

时间:2015-03-19 12:08:57

标签: c# .net linq dictionary datatable

DataTable具有以下列名称:

Name, Value, Type, Info

需要转换结构词典

其中Name是Key(字符串),其他值将附加到StringBuilder,如&#34; Value,Type,Info&#34;但是可以有重复的Name列值,然后连续每个附加值StringBuilder将使用像?:这样的分隔符来描述下一组值。

例如:如果DataTable数据如下:

Name, Value, Type, Info

one     1     a   aa
one     11    b   bb
two     2     c   cc
two     22    dd  ddd
two     222   ee   eee

现在结果结构应该是:

Dictionary<String,StringBuilder> detail = new Dictionary<String,StringBuilder>
{
{[one],[1,a,aa?:11,b,bb},
{[two],[2,c,cc?:22,dd,ddd?:222,ee,eee}
}

使用for循环很容易实现相同,但我试图通过Linq来做,所以我尝试了类似的东西:

datatable.AsEnumerable.Select(row =>
{
  KeyValuePair<String,StringBuilder> kv = new  KeyValuePair<String,StringBuilder>();

 kv.key = row[Name];
 kv.Value = row[Value]+","+row[Type]+","+row[Info]

 return kv;
}).ToDictionary(y=>y.Key,y=>y.Value)

这段代码没有处理重复的键并因此附加,可能我需要使用SelectMany来展平结构,但是如何在给我一个上面指定的要求的字典时这样做,这样分隔符就可以了添加为现有密钥的值。任何可以指引我正确方向的指针。

2 个答案:

答案 0 :(得分:3)

编辑:

datatable.AsEnumerable()
          .GroupBy(r => (string)r["Name"])
          .Select(g => new
            {
                Key = g.Key,
                // Preferred Solution
                Value = new StringBuilder(
                             g.Select(r => string.Format("{0}, {1}, {2}",   
                                      r["Value"], r["Type"], r["Info"]))
                                 .Aggregate((s1, s2) => s1 + "?:" + s2))                    
                /*
                //as proposed by juharr
                Value = new StringBuilder(string.Join("?:", g.Select( r => string.Format("{0}, {1}, {2}", r["Value"], r["Type"], r["Info"]))))
                */
            })
          .ToDictionary(p => p.Key, p => p.Value);

答案 1 :(得分:3)

这样的事情应该有效,它可以避免一些复杂的Linq,它可能会让调试变得烦恼:

public static Dictionary<string, StringBuilder> GetData(DataTable table)
{
    const string delimiter = "?:";
    var collection = new Dictionary<string, StringBuilder>();

    // dotNetFiddle wasn't liking the `.AsEnumerable()` extension
    // But you should still be able to use it here
    foreach (DataRow row in table.Rows)
    {
        var key = (string)row["Name"];

        var @value = string.Format("{0},{1},{2}", 
                                   row["Value"], 
                                   row["Type"], 
                                   row["Info"]);

        StringBuilder existingSb;

        if (collection.TryGetValue(key, out existingSb))
        {
            existingSb.Append(delimiter + @value);
        }
        else
        {
            existingSb = new StringBuilder();
            existingSb.Append(@value);
            collection.Add(key, existingSb);
        }
    }

    return collection;
}