I have a string array that I want to convert to a Dictionary using Linq.
I want elements with a even index (including zero) to be keys and elements with an odd index to be values in the dictionary. I created a dictionary using a for loop:
string[] arr = new string[4];
arr[0] = "John";
arr[1] = "A";
arr[2] = "Luke";
arr[3] = "B";
Dictionary<string, string> myDict = new Dictionary<string, string>();
for (int i = 0; i < arr.Length - 1; i += 2)
{
myDict.Add(arr[i], arr[i + 1]);
}
//myDict -> { { "John", "A" },{"Luke","B"} }
And now I am curious how to do it with LINQ ToDictionary():
myDict = arr.ToDictionary();
You can put it like this (in case of Linq we can exploit Enumerable.Range as a loop):
string[] arr = new string[] {
"John", "A",
"Luke", "B",
}
var myDict = Enumerable
.Range(0, arr.Length / 2)
.ToDictionary(i => arr[2 * i],
i => arr[2 * i + 1]);
Console.WriteLine(string.Join(Environment.NewLine, myDict));
Outcome:
[John, A]
[Luke, B]
You can group by index divided by 2. Try this code:
string[] arr = new string[4];
arr[0] = "John";
arr[1] = "A";
arr[2] = "Luke";
arr[3] = "B";
var dict = arr.Select((s, i) => new {s, i})
.GroupBy(x => x.i / 2)
.ToDictionary(g => g.First().s, g => g.Last().s);
Related
I have a comma separated string with values as follows:
"File_name,cost_per_page,0.23,color_code,343,thickness,0.01".
I want to read cost_per_page = 0.23, color_code=343 and thickness=0.01.
How can I do this? I could do this by putting it to a list and reading successive element next to key string. Is there any other method?
The simplest (and therefor, probably the best) approach would be to simply use string.Split and then iterate the array:
var source = "File_name,cost_per_page,0.23,color_code,343,thickness,0.01";
var splitted = source.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries)
var result = new Dictionary<string, string>();
// Note: Starting from 1 to skip the "file_name"
// moving 2 indexes in each iteration,
// and ending at length - 2.
for(int i = 1; i < splitted.Length - 1; i+=2)
{
result.Add(splitted[i], splitted[i+1]);
}
I've tried to find a clever way to do it with linq, but the best I came up with is really not that clever at all:
var valuesWithIndexes = source
.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries)
.Skip(1)
.Select((v, i) => new {v, i});
var keys = valuesWithIndexes.Where(x => x.i % 2 == 0);
var values = valuesWithIndexes.Where(x => x.i % 2 == 1);
var dictionary = keys.Zip(values, (k, v) => new {k, v})
.ToDictionary(key => key.k,
val => val.v);
I think the simple for loop is a clear winner in this case.
I think that this is the simplest and best approach.
string str = "File_name,cost_per_page,0.23,color_code,343,thickness,0.01";
string[] array = str.Split(',');
Dictionary<string, double> dict = new Dictionary<string, double>();
for (int i = 1; i < array.Length - 1; i = i + 2)
{
string key = array[i];
double value = Double.Parse(array[i + 1], CultureInfo.InvariantCulture);
dict.Add(key, value);
}
You can also use the above code for a larger string (variable str has more key-value pairs).
I'd use linq.
Convert the string into a delimited array.
Set up a dictionary containing the first item...not sure if you want to do this. If not just remove the "d1" and "union" statements.
Run some Linq to create your dictionary based on even numbers.
Then if you really want to account for the first item, file_name, and you want that at the beginning of your dictionary then lastly you'd run the "union" statement.
string str = "File_name,cost_per_page,0.23,color_code,343,thickness,0.01";
string[] array = str.Split(',');
Dictionary<string, string> d1 = new Dictionary<string, string>()
{
{ array[0], "" }
};
Dictionary<string, string> d2 = array.Select((i, index) => (index > 0 && index % 2 == 0) ?
new { key = array[index - 1], value = i } : null).Where(i => i != null).ToDictionary(d => d.key, d => d.value);
Dictionary<string, string> result = d1.Union(d2).ToDictionary(k => k.Key, v => v.Value);
foreach (KeyValuePair<string, string> kvp in result)
Console.WriteLine(kvp.Key + ": " + kvp.Value);
return;
another, and probably cleaner approach:
This accounts for File_name as well. If you don't want it then add "index > 0" to the conditional operator where it checks for even.
string str = "File_name,cost_per_page,0.23,color_code,343,thickness,0.01";
string[] array = str.Split(',');
Dictionary<string, string> d2 = array.Select((i, index) => (index % 2 == 0) ?
new
{
key = (index == 0) ? i : array[index - 1],
value = (index == 0) ? "" : i
} : null).Where(i => i != null).ToDictionary(d => d.key, d => d.value);
foreach (KeyValuePair<string, string> kvp in d2)
Console.WriteLine(kvp.Key + ": " + kvp.Value);
Full working example in this fiddle.
All you need is to iterate while you haven't reached your string array end ensuring your index increments by 2 (field name, field value).
int i = 1;
var temp = s.Split(',').ToList();
while(i < temp.Count) {
i = i+2;
}
I have two arrays and i am trying to get all possible sum of each element with other element of two array and index of each element
int[] width = new int[2] {10,20 };
int[] height = new int[2] {30,40 };
result should like this (value / indexes)
10 width0
10+20 width0+width1
10+30 width0+height0
10+40 width0+height1
10+20+30 width0+width1+height0
10+20+40 width0+width1+height1
10+20+30+40 width0+width1+height0+height1
And so for each element in two array
I tried using permutation but I get other output
It is more easy to get all combinations from one array than two arrays. And as we see, you need to store indices and array names along with the value of the elements in collections. So, in my opinion the best option is to combine these two arrays in one dictionary, where the key will be the value of the numbers and the value will be [ArrayName + Index of item] (f.e width0, height1 and so on....)
So, let's combine these arrays in one dictionary:
int[] width = new int[2] { 10, 20 };
int[] height = new int[2] { 30, 40 };
var widthDictionary = width.ToList().Select((number, index) => new { index, number })
.ToDictionary(key => key.number, value => string.Format("width{0}", value.index));
var heightDictionary = height.ToList().Select((number, index) => new { index, number })
.ToDictionary(key => key.number, value => string.Format("height{0}", value.index));
// And here is the final dictionary
var totalDictionary = widthDictionary.Union(heightDictionary);
Then add this method to your class: (source)
public static IEnumerable<IEnumerable<T>> GetPowerSet<T>(List<T> list)
{
return from m in Enumerable.Range(0, 1 << list.Count)
select
from i in Enumerable.Range(0, list.Count)
where (m & (1 << i)) != 0
select list[i];
}
Then send your dictionary as an argument to this method and project this collection as you want with the help of the Select() method:
var sumOfCombinations = GetPowerSet(totalDictionary.ToList())
.Where(x => x.Count() > 0)
.Select(x => new
{
Numbers = x.Select(pair => pair.Key).ToList(),
DisplayValues = x.Select(pair => pair.Value).ToList()
})
.ToList();
And at the end you can display expected result as this:
sumOfCombinations.ForEach(x =>
{
x.Numbers.ForEach(number => Console.Write("{0} ", number));
x.DisplayValues.ForEach(displayValue => Console.Write("{0} ", displayValue));
Console.WriteLine();
});
And, the result is:
This is a play off of #Farhad Jabiyev's answer.
Declares a class called IndexValuePair. and uses foreach on widthList and heightList. to populate the 'Index' property of item instance.
Note: Index is a string.
Class & Static Function
public class IndexValuePair
{
public string Index {get;set;}
public int Value {get;set;}
}
public static IEnumerable<IEnumerable<T>> GetPowerSet<T>(List<T> list)
{
return from m in Enumerable.Range(0, 1 << list.Count)
select
from i in Enumerable.Range(0, list.Count)
where (m & (1 << i)) != 0
select list[i];
}
Main (Console)
static void Main(string[] args)
{
int[] width = new int[2] { 10, 20 };
int[] height = new int[2] { 30, 40 };
var wholeList = width.Select(val => new IndexValuePair() { Index = "width", Value = val }).ToList();
var heightList = height.Select(val => new IndexValuePair() { Index = "height", Value = val }).ToList();
var iteration = 0;
wholeList.ForEach(ivp => { ivp.Index = ivp.Index + count; count = iteration + 1; });
iteration = 0;
heightList.ForEach(ipv => { ivp.Index = ivp.Index + count; count = iteration + 1; });
wholeList.AddRange(heightList);
var sumOfCombinations = GetPowerSet(wholeList).Where(x => x.Count() > 0)
.Select(x => new { Combination = x.ToList(), Sum = x.Sum(ivp => ivp.Value) }).ToList();
StringBuilder sb = new StringBuilder();
sumOfCombinations.ForEach(ivp =>
{
ivp.Combination.ForEach(pair => sb.Append(string.Format("{0} ", pair.Value)));
sb.Append(string.Format("= {0} = ", x.Sum));
ivp.Combination.ForEach(pair=> sb.Append(string.Format("{0} + ", pair.Index)));
sb.Length -= 3;
Console.WriteLine(sb);
sb.Clear();
});
var key = Console.ReadKey();
}
Given two lists below in C#:
List<string> X = new List<string>({ "a", "b", "c", "d", "e", "f", "g", "h", "i"});
List<float> Y = new List<float> ({ 0.991f, 1.471f, 3.819f, 0.003f, 2.291f, 2.887f, 2.887f, 0, 1.0f});
What will be the cleanest/shortest way of sorting X using float values from Y to get the following output?
"h", "d", "a", "i", "b", "e", "f", "g", "c"
The order for the elements having the same float "key" does not matter.
If each string key is unique and each list is perfectly matched, you can use them as keys in a dictionary using zip from System.Reactive.
var dic = X.Zip(Y, (k, v) => new { k, v })
.ToDictionary(x => x.k, x => x.v);
Now, sort your newly formed dictionary by value.
var sortedDict = from entry in dic orderby entry.Value ascending select entry;
In a "one-liner" using query syntax, this becomes:
var dic = X.Zip(Y, (k, v) => new { k, v })
.ToDictionary(x => x.k, x => x.v);
.OrderBy(x => x.Value);
Here's one way:
IEnumerable<string> sorted = X
.Select((value, index) => new { Index = index, Value = value })
.OrderBy(o => Y[o.Index])
.Select(o => o.Value);
Basically:
Use .Select to project your List (X) into a new sequence of anonymous objects that contains the string from X and its index within the list.
Order the sequence by the corresponding value in Y.
Select the Value portion of the anonymous object to create a new sequence containing just the strings from X.
Example: https://dotnetfiddle.net/ZjZvBR
The following code follows the bubble sorting technique...
for(int i = 1; i < max; i++)
{
for(int j = 0; j < max - i; j++)
{
if(Y[j] > Y[j + 1])
{
int temp = X[j];
X[j] = X[j + 1];
X[j + 1] = temp;
int temp1 = Y[j];
Y[j] = Y[j + 1];
Y[j + 1] = temp1;
}
}
}
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]);
}
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.
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]);
Using ToDictionary:
int idx = 0;
var dict = b.ToDictionary(d => a[idx++]);
var result = a.ToDictionary(x => x, x => b[a.IndexOf(x)]);
I am trying to create a dictionary from 2 lists where one list contains keys and one list contains values. I can do it using for loop but I am trying to find if there is a way of doing it using LINQ.
Sample code will be helpfull. Thanks!!!!
In .NET4 you could use the built-in Zip method to merge the two sequences, followed by a ToDictionary call:
var keys = new List<int> { 1, 2, 3 };
var values = new List<string> { "one", "two", "three" };
var dictionary = keys.Zip(values, (k, v) => new { Key = k, Value = v })
.ToDictionary(x => x.Key, x => x.Value);
List<string> keys = new List<string>();
List<string> values = new List<string>();
Dictionary<string, string> dict = keys.ToDictionary(x => x, x => values[keys.IndexOf(x)]);
This of course assumes that the length of each list is the same and that the keys are unique.
UPDATE: This answer is far more efficient and should be used for lists of non-trivial size.
You can include the index in a Select expression to make this efficient:
var a = new List<string>() { "A", "B", "C" };
var b = new List<string>() { "1", "2", "3" };
var c = a.Select((x, i) => new {key = x, value = b[i]}).ToDictionary(e => e.key, e => e.value );
foreach (var d in c)
Console.WriteLine(d.Key + " = " + d.Value);
Console.ReadKey();
var dic = keys.Zip(values, (k, v) => new { k, v })
.ToDictionary(x => x.k, x => x.v);
You can use this code and working perfectly.
C# Code:
var keys = new List<string> { "Kalu", "Kishan", "Gourav" };
var values = new List<string> { "Singh", "Paneri", "Jain" };
Dictionary<string, string> dictionary = new Dictionary<string, string>();
for (int i = 0; i < keys.Count; i++)
{
dictionary.Add(keys[i].ToString(), values[i].ToString());
}
foreach (var data in dictionary)
{
Console.WriteLine("{0} {1}", data.Key, data.Value);
}
Console.ReadLine();
Output Screen: