在C#中将字典转换为对象列表

4

我有一个字典:

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

我想知道是否有更快的方法从字典中填充此列表。
目前我找到的解决方案是将简单字典转换为简单类型的List,如下所示:将字典转换为List。请帮助我将此解决方案应用到我的情况中。 如果有其他可以消除这种开销的解决方案,我也愿意尝试。
4个回答

8
您正在进行不必要的键查找:
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的解决方案,但那会较慢,而您要求的是最佳解决方案。


哦,哇,这真是个好建议,我会实施并看看效果如何。 - Ganesh Kamath - 'Code Frenzy'
@Fruchtzwerg 因为你的答案循环遍历键。尝试循环遍历KeyValuePairs并注意区别。另一个要点是,你不仅需要运行代码一次并比较执行时间,还需要运行它可能1000次并取平均时间。 - Zein Makki

7
您可以通过将字典的每个 KeyValuePair 投影到您的 QuestionAnswer 对象中来使用 LINQ 创建列表:
 var qaList = 
    valuesDict.Select(kvp => new QuestionAnswer { Question = kvp.Key, Answer = kvp.Value })
              .ToList()

嗨,Sergey,谢谢你的回答。在这种特定情况下,使用Linq比foreach是否有性能优势? - Ganesh Kamath - 'Code Frenzy'
@codefrenzy,无论是foreach还是Select都将使用由字典GetEnumerator调用返回的Enumerator。因此,这更多地涉及到编程的声明式与命令式风格。LINQ方法的主要开销将是生成结果的迭代器。但在进行任何过早的优化之前,我建议先测量性能。这可能会有1%的差异。 - Sergey Berezovskiy
@codefrenzy,您正在手动创建新列表,而Sergey正在通过LINQ进行操作,因此我会感到惊讶如果LINQ的方式会显着变慢。为什么不尝试在两种情况下测量性能并确定性能差异是否对您至关重要?至少这个解决方案看起来更优雅。 - Vadim Ovchinnikov
1
@codefrenzy:使用更易读/易于维护的方法,而不是在某些情况下可能快1毫秒的方法。 - Tim Schmelter

0
更快?嗯,是的,绝对的,直接迭代字典而不是 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);

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

0

基本上有两种常见的方法。使用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的执行速度约快30%,优于LINQ的方法。


当您将循环从键更改为字典条目时,现在 linqforeach 花费的时间多了2倍。来试试吧。 - Zein Makki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接