Martin R-L
Martin R-L

Reputation: 4047

How to convert a String[] to an IDictionary<String, String>?

How to convert a String[] to an IDictionary<String, String>?

The values at the indices 0,2,4,... shall be keys, and consequently values at the indices 1,3,5,... shall be values.

Example:

new[] { "^BI", "connectORCL", "^CR", "connectCR" }

=>

new Dictionary<String, String> {{"^BI", "connectORCL"}, {"^CR", "connectCR"}};

Upvotes: 3

Views: 992

Answers (8)

Abhijeet Nagre
Abhijeet Nagre

Reputation: 926

Pure Linq

  1. Select : Project original string value and its index.
  2. GroupBy : Group adjacent pairs.
  3. Convert each group into dictionary entry.

string[] arr = new string[] { "^BI", "connectORCL", "^CR", "connectCR" };

var dictionary = arr.Select((value,i) => new {Value = value,Index = i})
                .GroupBy(value => value.Index / 2)
                .ToDictionary(g => g.FirstOrDefault().Value, 
                                   g => g.Skip(1).FirstOrDefault().Value);

Upvotes: 0

Markus Johnsson
Markus Johnsson

Reputation: 4019

If you have Rx as a dependency you can do:

strings
    .BufferWithCount(2)
    .ToDictionary(
         buffer => buffer.First(), // key selector
         buffer => buffer.Last()); // value selector

BufferWithCount(int count) takes the first count values from the input sequence and yield them as a list, then it takes the next count values and so on. I.e. from your input sequence you will get the pairs as lists: {"^BI", "connectORCL"}, {"^CR", "connectCR"}, the ToDictionary then takes the first list item as key and the last ( == second for lists of two items) as value.

However, if you don't use Rx, you can use this implementation of BufferWithCount:

static class EnumerableX
{
    public static IEnumerable<IList<T>> BufferWithCount<T>(this IEnumerable<T> source, int count)
    {
        if (source == null)
        {
            throw new ArgumentNullException("source");
        }

        if (count <= 0)
        {
            throw new ArgumentOutOfRangeException("count");
        }

        var buffer = new List<T>();

        foreach (var t in source)
        {
            buffer.Add(t);

            if (buffer.Count == count)
            {
                yield return buffer;
                buffer = new List<T>();
            }
        }

        if (buffer.Count > 0)
        {
            yield return buffer;
        }
    }
}

Upvotes: 1

Martin R-L
Martin R-L

Reputation: 4047

FYI, this is what I ended up with using a loop and implementing it as an extension method:

internal static Boolean IsEven(this Int32 @this)
{
    return @this % 2 == 0;
}

internal static IDictionary<String, String> ToDictionary(this String[] @this)
{
    if ([email protected]())
        throw new ArgumentException( "Array doesn't contain an even number of entries" );

    var dictionary = new Dictionary<String, String>();

    for (var i = 0; i < @this.Length; i += 2)
    {
        var key = @this[i];
        var value = @this[i + 1];

        dictionary.Add(key, value);
    }

    return dictionary;
}

Upvotes: 0

kwcto
kwcto

Reputation: 3504

It looks like other people have already beaten me to it and/or have more efficient answers but I'm posting 2 ways:

A for loop might be the clearest way to accomplish in this case...

var words = new[] { "^BI", "connectORCL", "^CR", "connectCR" };

var final = words.Where((w, i) => i % 2 == 0)
                 .Select((w, i) => new[] { w, words[(i * 2) + 1] })
                 .ToDictionary(arr => arr[0], arr => arr[1])
                 ;

final.Dump();

//alternate way using zip

var As = words.Where((w, i) => i % 2 == 0);
var Bs = words.Where((w, i) => i % 2 == 1);

var dictionary = new Dictionary<string, string>(As.Count());

var pairs = As.Zip(Bs, (first, second) => new[] {first, second})
                .ToDictionary(arr => arr[0], arr => arr[1])
                ;

pairs.Dump();

Upvotes: 0

brunnerh
brunnerh

Reputation: 185140

Something like this maybe:

        string[] keyValues = new string[20];
        Dictionary<string, string> dict = new Dictionary<string, string>();
        for (int i = 0; i < keyValues.Length; i+=2)
        {
            dict.Add(keyValues[i], keyValues[i + 1]);
        }

Edit: People in the C# tag are damn fast...

Upvotes: 3

R. Martinho Fernandes
R. Martinho Fernandes

Reputation: 234604

I'd recommend a good old for loop for clarity. But if you insist on a LINQ query, this should work:

var dictionary = Enumerable.Range(0, array.Length/2)
                           .ToDictionary(i => array[2*i], i => array[2*i+1])

Upvotes: 11

CodesInChaos
CodesInChaos

Reputation: 108830

Dictionary<string,string> ArrayToDict(string[] arr)
{
    if(arr.Length%2!=0)
        throw new ArgumentException("Array doesn't contain an even number of entries");
    Dictionary<string,string> dict=new Dictionary<string,string>();
    for(int i=0;i<arr.Length/2;i++)
    {
      string key=arr[2*i];
      string value=arr[2*i+1];
      dict.Add(key,value);
    }
    return dict;
}

Upvotes: 8

Justin Niessner
Justin Niessner

Reputation: 245459

There's really no easy way to do this in LINQ (And even if there were, it's certainly not going to be clear as to the intent). It's easily accomplished by a simple loop though:

// This code assumes you can guarantee your array to always have an even number
// of elements.

var array = new[] { "^BI", "connectORCL", "^CR", "connectCR" };
var dict = new Dictionary<string, string>();

for(int i=0; i < array.Length; i+=2)
{
    dict.Add(array[i], array[i+1]);
}

Upvotes: 6

Related Questions