【问题标题】:convert dictionary to list of objects in C#将字典转换为 C# 中的对象列表
【发布时间】:2017-12-04 05:57:54
【问题描述】:

我有一本字典:

Dictionary<string, string> valuesDict = new Dictionary<string, string> {
    {“Q1”, “A1”},
    {“Q2”, “A2”},
    {“Q3”, “A3”},
    {“Q4”, “A4”} /*20000 Q and A pairs*/
};

为了将其加载到仅接受对象列表(属于 QuestionAnswer 类)的第三方接口,我手动将其转换为这样的列表

Public Class QuestionAnswer {
    Public string Question;
    Public string Answer;
}

然后在循环中创建 QuestionAnswer 类的对象

List<QuestionAnswer> qaList = new List<QuestionAnswer>();
foreach(var key in valuesDict.Keys) {
    qaList.add(new QuestionAnswer {Question = key, Answer = valuesDict[key]});
}

我想知道是否有更快的方法从字典中填充此列表。

到目前为止我发现了什么: 在寻找解决方案时,我遇到了一个将简单字典转换为简单类型列表的解决方案,如下所示:Convert dictionary to List<KeyValuePair> 有人可以帮我利用这个解决方案来解决我的问题吗? 我也愿意接受任何其他可以消除这种开销的解决方案。

【问题讨论】:

    标签: c# list dictionary


    【解决方案1】:

    您正在对密钥进行不必要的查找:

    foreach(var item in valuesDict) {
        qaList.add(new QuestionAnswer {Question = item.Key, Answer = item.Value});
    }
    

    您还可以在初始化时提供列表计数以避免调整大小:

    List<QuestionAnswer> qaList = new List<QuestionAnswer>(valuesDict.Keys.Count);
    

    您可以使用基于 LinQ 的解决方案,但那是 slower,您要求的是最佳解决方案。

    【讨论】:

    • 哦,哇,这真是个好建议,我会实施它,看看效果如何。
    • @Fruchtzwerg,因为您的答案在键上循环。尝试遍历 KeyValuePairs 并注意差异。还有一点,你不会运行一次代码并比较执行时间,你可能需要运行它 1000 次并取平均时间。
    【解决方案2】:

    您可以通过将字典中的每个 KeyValuePair 投影到您的 QuestionAnswer 对象中来使用 LINQ 创建一个列表:

     var qaList = 
        valuesDict.Select(kvp => new QuestionAnswer { Question = kvp.Key, Answer = kvp.Value })
                  .ToList()
    

    【讨论】:

    • 嗨,谢尔盖,感谢您的回答。在这种特定情况下,使用 Linq 而不是 foreach 是否有任何性能优势?
    • @codefrenzy foreach 和 Select 都将使用由字典 GetEnumerator 调用返回的 Enumerator。所以它更多的是关于声明式与命令式的编程风格。 LINQ 方法的主要开销将是产生结果的迭代器。但是我会在进行任何过早的优化之前测量性能。可能相差 1%
    • @codefrenzy 您正在手动创建新列表,而 Sergey 正在通过 LINQ 执行此操作,所以我很惊讶 LINQ 方式会明显变慢。您为什么不尝试在这两种情况下测量性能并确定性能差异对您来说是否至关重要?至少这个解决方案看起来更优雅。
    • @codefrenzy:使用您认为更具可读性/可维护性的内容,而不是在某些情况下可能快 1 毫秒的内容。
    【解决方案3】:

    更快?嗯,是的,绝对是,直接迭代字典,而不是 Keys 集合:

    foreach(var kv in valuesDicts) {
        qaList.add(new QuestionAnswer {Question = kv.Key, Answer = kv.Value});
    

    或者更好的是,使用System.Linq

    valuesDict.Select(kv => new QuestionAnswer(kv.Key, kv.Value);
    

    在您的代码中,您在每次迭代中都执行了不必要的键搜索。

    【讨论】:

      【解决方案4】:

      基本上有两种常见的方法。使用 foreach 或 LINQ。要检查性能,您可以使用秒表并运行如下简单代码:

      Dictionary<string, string> valuesDict = new Dictionary<string, string>();
      for (uint i = 0; i < 60000; i++)
      {
          valuesDict.Add(i.ToString(), i.ToString());
      }
      
      List<QuestionAnswer> qaList;
      Stopwatch stp = new Stopwatch();
      
      stp.Start();
      //LINQ approach
      qaList = valuesDict.Select(kv => new QuestionAnswer { Question = kv.Key, Answer = kv.Value }).ToList();
      stp.Stop();
      Console.WriteLine(stp.ElapsedTicks);
      
      stp.Restart();
      //Foreach approach
      qaList = new List<QuestionAnswer>();
      foreach (var item in valuesDict)
      {
          qaList.Add(new QuestionAnswer { Question = item.Key, Answer = item.Value });
      }
      stp.Stop();
      Console.WriteLine(stp.ElapsedTicks);
      

      我的结果:Foreach 的执行速度比 LINQ 方法快大约 30%

      【讨论】:

      • 在您将循环从 over 键更改为 over 字典条目之后。现在 linqforeach 多 2 倍。试一试。
      猜你喜欢
      • 2021-06-28
      • 2015-06-08
      • 2021-06-06
      • 1970-01-01
      • 2021-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-15
      相关资源
      最近更新 更多