Reputation: 100351
Given two IEnumerable
s 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
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
Reputation: 4886
If you use MoreLINQ, you can also utilize it's ToDictionary extension method on previously created KeyValuePair
s:
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
Reputation: 39319
I like this approach:
var dict =
Enumerable.Range(0, keys.Length).ToDictionary(i => keys[i], i => values[i]);
Upvotes: 19
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
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