Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I combine the keys and values of a Dictionary into one List using LINQ?

Tags:

c#

linq

I have a dictionary, where the key is a string and the value is a list of strings that correspond to that key. I would like to display all of the keys in the dictionary, with the values associated with that key tabbed in underneath that key. Something like this:

Key 1
    Value 1
    Value 2
    Value 3
Key 2
    Value 1
    Value 2

In C# 2.0, I would do that like this (values is the Dictionary):

StringBuilder sb = new StringBuilder();
foreach(KeyValuePair<string, List<string>> pair in values)
{
    sb.AppendLine(pair.Key);
    foreach(string item in pair.Value)
    {
        sb.AppendLine('\t' + item);
    }
}

How would I do the equivalent using LINQ? It seems like it should be possible, however I can't figure out how to do it.

If I use values.SelectMany(p => p.Values), then only the values will be in the final result, not the keys as well.

Any other solution that I've thought of has a similar limitation.

like image 662
Andy Avatar asked Apr 15 '09 19:04

Andy


People also ask

Can we get key from value in dictionary C#?

Unfortunately, there is no built-in method for getting the key by value from a dictionary in C#.

Can C# Dictionary have duplicate keys?

In Dictionary, the key cannot be null, but value can be. In Dictionary, key must be unique. Duplicate keys are not allowed if you try to use duplicate key then compiler will throw an exception. In Dictionary, you can only store same types of elements.


1 Answers

A Solution in C#

Here is a solution using the aggregate extension method:

string result = values.Aggregate("",
                  (keyString, pair) =>
                    keyString + "\n" + pair.Key + ":"
                      + pair.Value.Aggregate("",
                          (str, val) => str + "\n\t" + val)
                  );

There is no LINQ syntax for the aggregate clause in C# (but apparently there is in Visual Basic for some predefined functions).

This solution might look somewhat complex, but the aggregate method is quite useful.

How Aggregate works

It works like this: If you have a List<int> you can combine all values into a single aggregate value.

That is in contrast to the Select method, which doesn't modify the length of the list. Or the Where method, which does shrink the list, but it still remains a list (instead of a single value).

For example, if you have a list {1, 2, 3, 4} you can combine them into a single value like this:

int[] xs = {1, 2, 3, 4};
int sum = xs.Aggregate(0, (sumSoFar, x) => sumSoFar + x);

So you give two values to the Aggregate method; a seed value and a 'combiner' function:

  • You start aggregating with a single seed value (0 in this case).
  • Your combiner function gets called for each value in the list.
    The first argument is the computed result so far (zero the first time, later this will have other values), and it combines it with the value x.

That's in short how the Aggregate method works on List<int>. It works the same on KeyValuePair<string, List<string>>, but just with different types.

like image 108
Tom Lokhorst Avatar answered Sep 24 '22 05:09

Tom Lokhorst