How to convert String [] to IDictionary <String, String>?
How to convert a String[] to IDictionary<String, String> ?
The values ββin indices 0,2,4, ... must be keys, and therefore the values ββin indices 1,3,5, ... must be values.
Example:
new[] { "^BI", "connectORCL", "^CR", "connectCR" } =>
new Dictionary<String, String> {{"^BI", "connectORCL"}, {"^CR", "connectCR"}}; 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; } There really is no easy way to do this in LINQ (and even if it were, then, of course, it would not be clear as to the intention). This is easily achieved with a simple loop:
// 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]); } If you have Rx as a dependency you can make:
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 gives them as a list, then takes the next count values ββand so on. That is, from your input sequence you will get pairs in the form of lists: {"^BI", "connectORCL"}, {"^CR", "connectCR"} , ToDictionary then takes the first element of the list as the key and the last (== second for lists of two items) as a value.
However, if you are not using 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; } } } It seems that other people have already beaten me and / or received more effective answers, but I am sending 2 ways:
And for a loop, it might be the clearest way 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(); FYI, here's what I ended up with with 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 ( !@this.Length.IsEven ()) 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; } Pure Linq
- Select: the source string value of the project and its index.
- GroupBy: group adjacent pairs.
- Convert each group to a 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); code>