Map two lists into a dictionary in C#

49,215

Solution 1

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

Solution 2

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

Solution 3

I like this approach:

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

Solution 4

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.

Share:
49,215
BrunoLM
Author by

BrunoLM

I'm a Developer for Fun! Things I like Code Play games Anime / Manga Contact information [email protected] LinkedIn Facebook Site - https://brunolm.github.io/ Blog - http://blog.codingwise.com/

Updated on July 23, 2020

Comments

  • BrunoLM
    BrunoLM almost 4 years

    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
    
  • spender
    spender over 13 years
    Thumbs up for .Zip. Glad it's made it into the BCL. I've had my own version for quite some time.
  • Oliver
    Oliver over 13 years
    @spender - Even if you made your own, i would take it from Eric Lipperts Blog
  • leppie
    leppie over 13 years
    Pity there is a need for a Zip method. If only more statically typed languages would support generic variadic parameters, Select would handle this (like map in Scheme).
  • Nyerguds
    Nyerguds over 13 years
    Oh, beautiful! I was looking exactly for that. Linq is handy, but the code you need to write with it looks really confusing IMO.
  • June
    June over 9 years
    Brilliant ! Thank you
  • Romulus Urakagi Ts'ai
    Romulus Urakagi Ts'ai almost 2 years
    In 2022 it can be shorter as var dic = keys.Zip(values).ToDictionary(x => x.First, x => x.Second);