25

If you have two arrays string[] a and int[] b how can you get a Dictionary<string,int> from it most efficiently and with least code possible? Assume that they contain the same number of elements.

For example, is this the best way?

Dictionary<string,int> vals = new Dictionary<string,int>();
for(int i = 0; i < size; i++)
{
    vals.Add(a[i],b[i]);
}
Anthony Pegram
  • 123,721
  • 27
  • 225
  • 246
selion
  • 335
  • 1
  • 3
  • 6
  • Do you mean to make a dictionary with keys from the string[] a and values from the int[] b (presuming they're the same size)? – karmakaze May 26 '11 at 03:29
  • 3
    The method you just added is indeed fairly simple and straightforward. Yes, you can do a one-liner with Linq, but compare your code with the examples in the answers, including mine. Is the Linq version easier to understand or harder? – Anthony Pegram May 26 '11 at 03:37
  • thanks, I'll use my method but didn't know 4.0 aded Zip method:) What a cool name. But for this case I think functional style with anonymous type & method it may be harder + just like me people can wonder what is Zip and then be like it's Zip:) – selion May 26 '11 at 03:51
  • I think your method is the best. First its more readable than using Linq and second it is most likely the faster. – Richard Schneider May 26 '11 at 03:59
  • For a simple task like this the straight forward method (as you have written it) is fine. Using LINQ to save one line of code (which you don't if you look at it) will slow down the process considerably. The method calls involved in LINQ ZIP are relatively expensive. If speed is an issue the question should be if there is a way to batch-update a dictionary. – Tedd Hansen May 26 '11 at 12:04

4 Answers4

42

If your goal is to match at positions within the sequences, you can use Enumerable.Zip.

int[] myInts = { 1, 2 };
string[] myStrings = { "foo", "bar"};

var dictionary = myStrings.Zip(myInts, (s, i) => new { s, i })
                          .ToDictionary(item => item.s, item => item.i);

And since you are working with arrays, writing it "longhand" really isn't all that long. However, you want to validate beforehand the arrays truly are equal in length.

var dictionary = new Dictionary<string, int>();

for (int index = 0; index < myInts.Length; index++)
{
    dictionary.Add(myStrings[index], myInts[index]);
}

Usually, Linq can result in more expressive, easier to understand code. In this case, it's arguable the opposite is true.

Anthony Pegram
  • 123,721
  • 27
  • 225
  • 246
16

If this is .Net 4, then you can do the following:

var result = a.Zip(b, (first, second) => new {first, second})
    .ToDictionary(val => val.first, val => val.second);

Without Zip, you can also do this:

var result = Enumerable.Range(0, a.Length).ToDictionary(i => a[i], i => b[i]);
Servy
  • 202,030
  • 26
  • 332
  • 449
Chris Pitman
  • 12,990
  • 3
  • 41
  • 56
  • 5
    I might be in the minority but I actually prefer the Enumerable.Range solution. Easier on the eyes. – Todd Menier Jun 12 '14 at 17:23
  • @ToddMenier Your edit is incorrect. The second argument to `Range` is the number of items to yield, not the inclusive outer bounds. Your edit results in the last item being skipped. – Servy Jun 12 '14 at 17:28
  • Right you are, thanks for catching that. I have an odd situation where my start index is 1, got an out-of-range exception and made a bad assumption as to why. – Todd Menier Jun 12 '14 at 17:38
  • 1
    @ToddMenier agreed! I wish this was the top answer :) I also feel like it's logically simpler - it's just going from a list of integers, to key value pairs made up of items at that position in each array. I suppose the zip approach is very similar - but you don't need an intermediate data type. – Ian Grainger Dec 07 '15 at 12:08
1

Using ToDictionary:

        int idx = 0;
        var dict = b.ToDictionary(d => a[idx++]);
Sergiy
  • 1,912
  • 2
  • 16
  • 25
-1
var result = a.ToDictionary(x => x, x => b[a.IndexOf(x)]);
user3814929
  • 159
  • 2
  • 6