4

I have a dictionary:

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

Inorder to load this to a third party interface which only accepts a list of objects (of class QuestionAnswer), I am manually converting it to a list like so

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

objects of the QuestionAnswer class are then created within the loop

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

I want to know if there is a faster way to populate this list from the dictionary.

What I have found so far: While looking around for the solution, I came across a solution for a conversion of simple Dictionary to List of simple types like so: Convert dictionary to List<KeyValuePair> Could someone please help me in utilizing this solution to my case please. I am also open to any other solution that can remove this overhead.

4 Answers4

8

You're doing an unnecessary lookup for the key:

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

You can also provide the list count when intializing to avoid resize:

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

You can use LinQ-based solutions, but that is slower and you're asking for optimal solution.

Zein Makki
  • 29,485
  • 6
  • 52
  • 63
  • oh, wow, that is really good suggestion, I will implement this and see how it goes. – Ganesh Kamath - 'Code Frenzy' Jun 30 '17 at 10:04
  • @Fruchtzwerg because your answer loops over keys. Try looping over KeyValuePairs and notice the difference. Another point, you don't run a code once and compare execution time, you need to run it maybe 1000 times and take the average time. – Zein Makki Jun 30 '17 at 10:23
7

You can create a list with LINQ by projecting each KeyValuePair of the dictionary into your QuestionAnswer object:

 var qaList = 
    valuesDict.Select(kvp => new QuestionAnswer { Question = kvp.Key, Answer = kvp.Value })
              .ToList()
Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
  • Hi Sergey, thank you for your answer. Is there any performance benefit in using Linq over foreach, in this specific case? – Ganesh Kamath - 'Code Frenzy' Jun 30 '17 at 10:00
  • @codefrenzy both foreach and Select will use `Enumerator` returned by dictionary `GetEnumerator` call. So it's more about declarative vs imperative style of programming. Main overhead of LINQ approach will be iterator which yields results. But I would measure performance before making any premature optimization. It might differ 1% – Sergey Berezovskiy Jun 30 '17 at 10:02
  • @codefrenzy You are creating new list manually and Sergey is doing this via LINQ so I would be surprised that LINQ way will be significantly slower. Why don't you try and measure performance in both cases and determine if the difference in performance is critical for you? At least this solution looks more elegant. – Vadim Ovchinnikov Jun 30 '17 at 10:03
  • 1
    @codefrenzy: Use what you find more readable/maintainable, not what might be 1ms faster under certain circumstances. – Tim Schmelter Jun 30 '17 at 10:13
0

Faster? Well, yes, absolutely, iterate directly the dictionary, not the Keys collection:

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

Or better yet, using System.Linq:

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

In your code you are performing an unecessary key search on each iteration.

InBetween
  • 32,319
  • 3
  • 50
  • 90
0

Basically ther are two common approaches. Using a foreach or LINQ. To check the performance you can use a stopwatch and run a simple code like this:

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

My result: Foreach performes about 30% faster than the LINQ approach.

Fruchtzwerg
  • 10,999
  • 12
  • 40
  • 49
  • After you changed the loop from over keys to over dictionary entries. Now **linq** takes 2 times more than **foreach**. Give it a try. – Zein Makki Jun 30 '17 at 10:26