【问题标题】:Conversion of DataTable to Dictionary<String,StringBuilder>将 DataTable 转换为 Dictionary<String,StringBuilder>
【发布时间】:2015-03-19 12:08:56
【问题描述】:

DataTable 具有以下列名称:

Name, Value, Type, Info

需要转换结构字典

其中 Name 是键(字符串),其他值将附加到 StringBuilder,如“Value,Type,Info”,但是可能有重复的 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 来展平结构,但它如何为我提供具有上述要求的字典,以便可以添加分隔符是现有键的值。任何可以指引我正确方向的指针。

【问题讨论】:

  • 为什么StringBuilderValue
  • 这是为了方便附加字符串,而不是使用像 String.Join 这样的东西。这将是有效的
  • @MrinalKamboj 您打算在创建字典后添加任何内容吗?如果不是,那么 StringBuilder 作为结果类型可能不是很有用。也不要假设string.Join 的效率低于没有基准标记的StringBuilder。据你所知,string.Join 使用 StringBuilder 或更好的东西。
  • 这是一个question,特别是关于string.JoinStringBuilder
  • @juharr 在这种情况下是的,一旦创建了 Dictionary,然后对于给定的键,我们将值附加到 StringBuilder 值中。说 SB 高效的想法是考虑到它在这种情况下的用法。我确信在我们的场景中进行基准标记不会有很大的不同

标签: c# .net linq dictionary datatable


【解决方案1】:

已编辑:

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

【讨论】:

  • ValueStringBuilder,而不是 OP 中的 String
  • 有趣让我试试这个,它会确保 StringBuilder 中的最后一个字符串不会在它之后得到分隔符“?:”
  • @VMAtm 使用StringBuilder 的全部意义在于所有字符串连接,这是在Aggregate 中完成的,所以此时它可能只是一个string .除非 OP 计划在以后添加更多内容。
  • @juharr 我假设 OP 将在其他字符串操作中使用字典中的值。
  • 你可以像string.Join("?:", g.Select(r =&gt; string.Format(...)))一样使用string.Join,而不是Aggregate。那应该更有效率。
【解决方案2】:

这样的东西应该可以工作,并且它避免了一些可能会刺激调试的复杂 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;
}

【讨论】:

  • 我喜欢你的解决方案。字典使用自己的值(字符串构建器)来构建自己,因此它应该比我的解决方案更有效。
  • @Cameron 正如我的问题中所建议的那样,我们已经使用您建议的解决方案进行了操作,我想找出使用​​ Linq 的解决方案。我当前的代码看起来几乎一样:)
  • @MrinalKamboj 我在发布答案后看到了这一点,并且认为没有必要删除,因为它提供了一个不是 Linq 的解决方案。但是,感谢您对为什么不接受我的回答的评论。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-22
  • 2021-05-19
  • 1970-01-01
相关资源
最近更新 更多