BrunoLM
BrunoLM

Reputation: 100351

Map two lists into a dictionary in C#

Given two IEnumerables of the same size, how can I convert it to a Dictionary using Linq?

IEnumerable<string> keys = new List<string>() { "A", "B", "C" };
IEnumerable<string> values = new List<string>() { "Val A", "Val B", "Val C" };

var dictionary = /* Linq ? */;

And the expected output is:

A: Val A
B: Val B
C: Val C

I wonder if there is some simple way to achieve it.

And should I be worried about performance? What if I have large collections?


I don't if there is an easier way to do it, currently I'm doing like this:

I have an Extension method that will loop the IEnumerable providing me the element and the index number.

public static class Ext
{
    public static void Each<T>(this IEnumerable els, Action<T, int> a)
    {
        int i = 0;
        foreach (T e in els)
        {
            a(e, i++);
        }
    }
}

And I have a method that will loop one of the Enumerables and with the index retrieve the equivalent element on the other Enumerable.

public static Dictionary<TKey, TValue> Merge<TKey, TValue>(IEnumerable<TKey> keys, IEnumerable<TValue> values)
{
    var dic = new Dictionary<TKey, TValue>();

    keys.Each<TKey>((x, i) =>
    {
        dic.Add(x, values.ElementAt(i));
    });

    return dic;
}

Then I use it like:

IEnumerable<string> keys = new List<string>() { "A", "B", "C" };
IEnumerable<string> values = new List<string>() { "Val A", "Val B", "Val C" };

var dic = Util.Merge(keys, values);

And the output is correct:

A: Val A
B: Val B
C: Val C

Upvotes: 99

Views: 65848

Answers (5)

user213769
user213769

Reputation: 688

Starting from .NET Core 3.0, you can just use the improved Zip() :

var dictionary = keys.Zip(values).ToDictionary(x => x.First, x => x.Second);

Define an extension method for this case, and you're as good as you can get :)

Upvotes: 4

Deilan
Deilan

Reputation: 4886

If you use MoreLINQ, you can also utilize it's ToDictionary extension method on previously created KeyValuePairs:

var dict = Enumerable
    .Zip(keys, values, (key, value) => KeyValuePair.Create(key, value))
    .ToDictionary();

It also should be noted that using Zip extension method is safe against input collections of different lengths.

Upvotes: 3

Todd Menier
Todd Menier

Reputation: 39319

I like this approach:

var dict =
   Enumerable.Range(0, keys.Length).ToDictionary(i => keys[i], i => values[i]);

Upvotes: 19

dahlbyk
dahlbyk

Reputation: 77540

Or based on your idea, LINQ includes an overload of Select() that provides the index. Combined with the fact that values supports access by index, one could do the following:

var dic = keys.Select((k, i) => new { k, v = values[i] })
              .ToDictionary(x => x.k, x => x.v);

(If values is kept as List<string>, that is...)

Upvotes: 36

dahlbyk
dahlbyk

Reputation: 77540

With .NET 4.0 (or the 3.5 version of System.Interactive from Rx), you can use Zip():

var dic = keys.Zip(values, (k, v) => new { k, v })
              .ToDictionary(x => x.k, x => x.v);

Upvotes: 182

Related Questions