Below is the code where key is being hard-coded in Dictionary
var datalist = new List<IDictionary<string, string>>();
for (var i = 0; i < dt.Rows.Count; ++i)
{
var data = new Dictionary<string, string>()
{
{ "ID", Convert.ToString(dt.Rows[i]["ID"]) },
{ "STATUS", Convert.ToString(dt.Rows[i]["Name"]) },
{ "TYPE", Convert.ToString(dt.Rows[i]["TYPE"]) }
};
datalist.Add(data);
}
Now, instead of hard-coding the keys like ID, STATUS, etc, I want to add it from my string array containing the values below
string[] arrNames = ConfigurationManager.AppSettings["NameKey"].Split(',');
How can I traverse arrNamesto add keys in Dictionary and then add in List?
Iterate through the collection of names:
var datalist = new List<IDictionary<string, string>>();
string[] arrNames = ConfigurationManager.AppSettings["NameKey"].Split(',');
for (var i = 0; i < dt.Rows.Count; ++i)
{
var data = new Dictionary<string, string>();
foreach (var name in arrNames)
{
data[name] = Convert.ToString(dt.Rows[i][name]);
}
datalist.Add(data);
}
your code should look something like this
var datalist = new List<IDictionary<string, string>>();
string[] arrNames = Convert.ToString(ConfigurationManager.AppSettings["NameKey"]).Split(',');
if (arrNames.Length == 3)
{
for (var i = 0; i < dt.Rows.Count; ++i)
{
var data = new Dictionary<string, string>()
{
{ arrNames[0], Convert.ToString(dt.Rows[i][arrNames[0]]) },
{ arrNames[1], Convert.ToString(dt.Rows[i][arrNames[1]]) },
{ arrNames[2], Convert.ToString(dt.Rows[i][arrNames[2]]) }
};
datalist.Add(data);
}
}
You can use linq method ToDictionary. Try this code:
string[] arrNames = // new[] {"ID", "STATUS", "TYPE"};
var datalist = new List<IDictionary<string, string>>();
for (var i = 0; i < dt.Rows.Count; ++i)
datalist.Add(
arrNames
.Select(key =>
new
{
key,
value = Convert.ToString(dt.Rows[i][key])
}
)
.ToDictionary(x => x.key, x => x.value)
);
If you prefer LINQ-y and concise you could try something like:
var names = ConfigurationManager.AppSettings["NameKey"].Split(',');
var list = dt.AsEnumerable()
.Select(r => names.ToDictionary(n => n, n => r[n]))
.ToList();
Here I'm assuming dt is a DataTable.
If you have at least the same number of items in your arrNames array than columns you want to read and of course with this order, then you can hardcore the indexes.
var datalist = new List<IDictionary<string, string>>();
for (var i = 0; i < dt.Rows.Count; ++i)
{
var data = new Dictionary<string, string>()
{
{ arrNames[0], Convert.ToString(dt.Rows[i]["ID"]) },
{ arrNames[1], Convert.ToString(dt.Rows[i]["Name"]) },
{ arrNames[2], Convert.ToString(dt.Rows[i]["TYPE"]) }
};
datalist.Add(data);
}
Related
I am trying to converting from dictionary to list while converting I am getting the output
I/p-
dic.Add("Demo1",2);
dic.Add("Demo2",1);
dic.Add("Demo3",1);
dic.Add("Demo4",2);
O/p-
Demo1
Demo2
Demo3
Demo4
But I need Demo1 and Demo4 two times because their quantity are 2. So How can I achieve that??
Below is the code
public IList<string> DictionaryToList(IDictionary<string,int> dictionary)
{
IDictionary<string, int> dic = new Dictionary<string, int>();
IList<string> lst = new List<string>();
dic.Add("Demo1",2);
dic.Add("Demo2",1);
dic.Add("Demo3",1);
dic.Add("Demo4",2);
foreach (var item in dic)
{
if (!lst.Contains(item.Key))
{
lst.Add(item.Key);
}
}
return lst;
}
}
class Program
{
static void Main(string[] args)
{
var conversion = new Conversion();
var list = new List<string> { "Demo1","Demo2","Demo3","Demo4","Demo1","Demo4"};
var dictionary = conversion.ListToDictionary(list);
foreach (var item in dictionary)
{
Console.WriteLine($"{item.Key}, {item.Value}");
}
var convertedList = conversion.DictionaryToList(dictionary);
foreach (var item in convertedList)
{
Console.WriteLine($"{item}");
}
Console.ReadLine();
}
Thanks in advance.
You can use LINQ's SelectMany and Enumerable.Repeat:
IList<string> list = dictionary
.SelectMany(kv => Enumerable.Repeat(kv.Key, kv.Value))
.ToList();
Here is also the opposite way to build your dictionary from the list:
var list = new List<string> { "Demo1", "Demo2", "Demo3", "Demo4", "Demo1", "Demo4" };
var dictionary = list.GroupBy(s => s).ToDictionary(g => g.Key, g => g.Count());
IList<string> list2 = dictionary
.SelectMany(kv => Enumerable.Repeat(kv.Key, kv.Value))
.ToList();
So at the end list2 contains the same strings as list but in a different order.
Your dictionary consists of a key (string) and a value (int). After checking
if (!list.Contains(item.Key)) just add another loop which goes from 0 to the actual value from your dictionary-item and adds the new item n-times.
for (int i = 0; i < item.Value; i++) // Demo1 and Demo4 runs 2x, Demo2 and Demo3 1x
lst.Add(item.Key);
Do you want something like this?
Dictionary<string, int> dic = new Dictionary<string, int>();
List<string> lst = new List<string>();
dic.Add("Demo1", 2);
dic.Add("Demo2", 1);
dic.Add("Demo3", 1);
dic.Add("Demo4", 2);
foreach (var item in dic)
{
for (int i = 0; i < item.Value; i++)
{
lst.Add(item.Key);
}
}
I'm currently making a program that tracks certain things (basic INT Values and the Date when they were saved).
My goal is to add up the INT values with the same Date.
20.11.2018 00:00:00; 1;1;1;1;1
20.11.2018 00:00:00; 1;1;1;1;1
22.11.2018 00:00:00; 1;1;1;1;1
Should basically look like this
20.11.2018 00:00:00; 2;2;2;2;2
22.11.2018 00:00:00; 1;1;1;1;1
The Saving Data and even the adding the 2 "Lines" together is working perfectly fine.
The problem is that When I add the Lines together, the 2 Lines with the 1 obviously don't get deleted.
This is the Method that Compares the Date and adds the lines together:
public static Dictionary<DateTime, int[]> CompareDateMethod(Dictionary<DateTime, int[]> oDateTimeAndIntDictionary,string[][] ReadData)
{
Dictionary<DateTime, int[]> oPrintRealData = new Dictionary<DateTime, int[]>();
Dictionary<DateTime, int[]> oAddRealData = new Dictionary<DateTime, int[]>();
for (int i = 0 ; i < ReadData.Length; i++)
{
DateTime dtDateValue;
if (DateTime.TryParse(ReadData[i][0], out dtDateValue))
{
int[] iValuesToAdd = ConvertArrayToInt(ReadData[i]);
if (dtDateValue.Date == DateTime.Now.Date)
{
for (int j = 0; j < iValuesToAdd.Length; j++)
{
oDateTimeAndIntDictionary[dtDateValue.Date][j] += iValuesToAdd[j];
}
}
else if (dtDateValue.Date != DateTime.Now.Date)
{
goto Endloop;
}
}
}
Endloop:
return oDateTimeAndIntDictionary;
This is the method that Writes the Data into the .CSV file
Dictionary<DateTime, int[]> oDateTimeAndIntDictionary = new Dictionary<DateTime, int[]>();
string[][] OldData= AddVariables.ReadOldData();
int[] iNewDataArray = new int[] { iVariable1, iVariable2, iVariable3, iVariable4, iVariable5};
oDateTimeAndIntDictionary.Add(DateTime.Now.Date, iNewDataArray);
using (System.IO.FileStream fileStream = new System.IO.FileStream(#"C: \Users\---\Csvsave\SaveDatei.csv", System.IO.FileMode.Append, System.IO.FileAccess.Write))
using (System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(fileStream))
{
foreach (KeyValuePair<DateTime, int[]> kvp in AddVariables.CompareDateMethod(oDateTimeAndIntDictionary, OldData))
{
streamWriter.WriteLine("{0}; {1}", kvp.Key, string.Join(";", kvp.Value));
}
}
I tried so hard to come up with something but nothing worked (I tried deleting lines from the .csv which seems really hard, I tried reading the file in backwards which didnt work etc.)
If someone can give me some pointers I would really appreciate it.
I think the problem with the original code is that it's a bit confused about what happens when. I've restructured it so that things happen in a logical order (and updated it a bit, simplifying variable names, etc). There's one function for combining rows with the same date, which is separate from the CSV writing code (which hasn't changed)
static void Main(string[] args)
{
var oldData = ReadOldData();
// Do the work
var results = SumValuesForSameDate(oldData);
// Write the file
using (System.IO.FileStream fileStream = new System.IO.FileStream(#"C: \Users\---\Csvsave\SaveDatei.csv", System.IO.FileMode.Append, System.IO.FileAccess.Write))
using (System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(fileStream))
{
foreach (KeyValuePair<DateTime, int[]> kvp in results)
{
streamWriter.WriteLine("{0}; {1}", kvp.Key, string.Join(";", kvp.Value));
}
}
}
public static Dictionary<DateTime, int[]> SumValuesForSameDate(string[][] readData)
{
var oDateTimeAndIntDictionary = new Dictionary<DateTime, int[]>();
var currentDate = DateTime.MinValue;
foreach (var row in readData)
{
DateTime dateValue;
if(!DateTime.TryParse(row[0], out dateValue)) continue;
dateValue = dateValue.Date;
var intValues = ConvertArrayToInt(row);
if (dateValue == currentDate)
{
for (var j = 0; j < intValues.Length; j++)
{
oDateTimeAndIntDictionary[dateValue][j] += intValues[j];
}
}
else
{
oDateTimeAndIntDictionary.Add(dateValue, intValues);
currentDate = dateValue;
}
}
return oDateTimeAndIntDictionary;
}
static int[] ConvertArrayToInt(string[] strings)
{
var output = new int[strings.Length - 1];
for (var i = 1; i < strings.Length; i++)
{
output[i - 1] = int.Parse(strings[i]);
}
return output;
}
static string[][] ReadOldData()
{
// Fake data
var data = new string[][]
{
new string[] { "20.11.2018 00:00:00", "1", "1", "1", "1", "1" },
new string[] { "20.11.2018 00:00:00", "1", "1", "1", "1", "1" },
new string[] { "22.11.2018 00:00:00", "1", "1", "1", "1", "1" },
};
return data;
}
}
For overwriting the previous CSV just use System.IO.FileMode.Create instead of Append. This will overwrite any previous data.
You need to overwrite the csv anyways to get rid of the written row.
So instead of returning oDateTimeAndIntDictionary from CompareDateMethod method, return ReadData and overwrite the parsed values of ReadData.
Something like this,
public static Dictionary<DateTime, int[]> CompareDateMethod(Dictionary<DateTime, int[]> oDateTimeAndIntDictionary,string[][] ReadData)
{
Dictionary<DateTime, int[]> oPrintRealData = new Dictionary<DateTime, int[]>();
Dictionary<DateTime, int[]> oAddRealData = new Dictionary<DateTime, int[]>();
for (int i = 0 ; i < ReadData.Length; i++)
{
DateTime dtDateValue;
if (DateTime.TryParse(oDateTimeAndIntDictionary[0][0], out dtDateValue))
{
int[] iValuesToAdd = ConvertArrayToInt(ReadData[i]);
if (dtDateValue.Date == DateTime.Now.Date)
{
for (int j = 0; j < iValuesToAdd.Length; j++)
{
//Add the ReadData values here and store at ReadData[i][j]
}
}
else if (dtDateValue.Date != DateTime.Now.Date)
{
goto Endloop;
}
}
}
Endloop:
return ReadData;
}
Hope this helps...
I readed your comment about not using linq and 3rd part lib too late.
But let me show you what you are missing.
Here it's a little Linq + CSVHelper
First Lest define your data, and define how to map them in the CSV
public sealed class data
{
public DateTime TimeStamp { get; set; }
public List<int> Numbers { get; set; }
}
public sealed class dataMapping : ClassMap<data>
{
public dataMapping()
{
Map(m => m.TimeStamp).Index(0);
Map(m => m.Numbers)
.ConvertUsing(
row =>
new List<int> {
row.GetField<int>(1),
row.GetField<int>(2),
row.GetField<int>(3)
}
);
}
}
And now this is a short demo:
class CsvExemple
{
string inputPath = "datas.csv";
string outputPath = "datasOut.csv";
List<data> datas;
public void Demo()
{
//no duplicate row in orginal input
InitialiseFile();
LoadExistingData();
//add some new row and some dupe
NewDatasArrived();
//save to an other Path, to Compare.
SaveDatas();
}
private void SaveDatas()
{
using (TextWriter writer = new StreamWriter(outputPath))
using (var csvWriter = new CsvWriter(writer))
{
csvWriter.Configuration.RegisterClassMap<dataMapping>();
csvWriter.Configuration.Delimiter = ";";
csvWriter.Configuration.HasHeaderRecord = false;
csvWriter.WriteRecords(datas);
}
}
static List<int> SuperZip(params List<int>[] sourceLists)
{
for (var i = 1; i < sourceLists.Length; i++)
{
sourceLists[0] = sourceLists[0].Zip(sourceLists[i], (a, b) => a + b).ToList();
}
return sourceLists[0];
}
private void NewDatasArrived()
{
var now = DateTime.Today;
// New rows
var outOfInitialDataRange = Enumerable.Range(11, 15)
.Select(x => new data { TimeStamp = now.AddDays(-x), Numbers = new List<int> { x, x, x } });
// Duplicate rows
var inOfInitialDataRange = Enumerable.Range(3, 7)
.Select(x => new data { TimeStamp = now.AddDays(-x), Numbers = new List<int> { x, x, x } });
//add all of them them together
datas.AddRange(outOfInitialDataRange);
datas.AddRange(inOfInitialDataRange);
// all this could have been one Line
var grouped = datas.GroupBy(x => x.TimeStamp);
var temp = grouped.Select(g => new { TimeStamp = g.Key, ManyNumbers = g.Select(x => x.Numbers).ToArray() });
// We can combine element of 2 list using Zip. ListA.Zip(ListB, (a, b) => a + b)
datas = temp.Select(x => new data { TimeStamp = x.TimeStamp, Numbers = SuperZip(x.ManyNumbers) }).ToList();
}
private void LoadExistingData()
{
if (File.Exists(inputPath))
{
using (TextReader reader = new StreamReader(inputPath))
using (var csvReader = new CsvReader(reader))
{
csvReader.Configuration.RegisterClassMap<dataMapping>();
csvReader.Configuration.HasHeaderRecord = false;
csvReader.Configuration.Delimiter = ";";
datas = csvReader.GetRecords<data>().ToList();
}
}
else
{
datas = new List<data>();
}
}
private void InitialiseFile()
{
if (File.Exists(inputPath))
{
return;
}
var now = DateTime.Today;
var ExistingData = Enumerable.Range(0, 10)
.Select(x => new data { TimeStamp = now.AddDays(-x), Numbers = new List<int> { x, x, x } });
using (TextWriter writer = new StreamWriter(inputPath))
using (var csvWriter = new CsvWriter(writer))
{
csvWriter.Configuration.RegisterClassMap<dataMapping>();
csvWriter.Configuration.Delimiter = ";";
csvWriter.Configuration.HasHeaderRecord = false;
csvWriter.WriteRecords(ExistingData);
}
}
}
I am trying to achieve the output by using multidimensional array which I can get by using KeyValuePair.
Input:
var foodPair = new Dictionary<string, string>
{
{"Pizza", "Italian"},
{"Curry", "Indian"},
{"Masala", "Indian"}
};
var teamPreference = new Dictionary<string, string>
{
{"Jose", "Italian" },
{"John", "Indian" },
{"Sarah", "Thai" },
{"Mary", "*" }
};
* means give everything
If selected food type is not available than give nothing. i.e Thai
Output:
Jose, Pizza
John, Curry
John, Masala
Mary, Pizza
Mary, Curry
Mary, Masala
Working Result by using KeyValuePair<string, string>:
https://dotnetfiddle.net/hNdlfy
I want to achieve same result by using string[,] but I don't know how to insert in dimensional array. Basically I am trying to learn how multidimensional arrays works by doing this kind of example.
You cannot "insert" in any array (single-dimensional or multidimensional). But you can create array with enough space.
var foodPair = new Dictionary<string, string> { { "Pizza", "Italian" }, { "Curry", "Indian" }, { "Masala", "Indian" } };
var teamPreference = new Dictionary<string, string> { { "Jose", "Italian" }, { "John", "Indian" }, { "Sarah", "Thai" }, { "Mary", "*" } };
var results = new List<KeyValuePair<string, string>>();
var results2 = new string[10, 2];
int rowIndex = 0;
foreach (var teamMember in teamPreference)
{
switch (teamMember.Key)
{
case "Jose":
var key = foodPair.FirstOrDefault(x => x.Value == "Italian").Key;
results.Add(new KeyValuePair<string, string>(teamMember.Key, key));
results2[rowIndex, 0] = teamMember.Key;
results2[rowIndex, 1] = key;
rowIndex++;
break;
case "John":
var getAll = foodPair.Where(x => x.Value == "Indian").ToList();
if (getAll.Any())
{
results.AddRange(getAll.Select(a => new KeyValuePair<string, string>(teamMember.Key, a.Key)));
}
foreach (var item in getAll)
{
results2[rowIndex, 0] = teamMember.Key;
results2[rowIndex, 1] = item.Key;
rowIndex++;
}
break;
case "Sarah":
var c = foodPair.FirstOrDefault(x => x.Value == "Thai").Key;
if (!string.IsNullOrEmpty(c))
{
results.Add(new KeyValuePair<string, string>(teamMember.Key, c));
}
if (!string.IsNullOrEmpty(c))
{
results2[rowIndex, 0] = teamMember.Key;
results2[rowIndex, 1] = c;
rowIndex++;
}
break;
case "Mary":
if (teamMember.Value == "*")
{
var everything = foodPair.Keys.ToList();
if (everything.Any())
{
results.AddRange(everything.Select(food => new KeyValuePair<string, string>(teamMember.Key, food)));
}
foreach (var item in everything)
{
results2[rowIndex, 0] = teamMember.Key;
results2[rowIndex, 1] = item;
rowIndex++;
}
}
break;
}
}
if (results.Any())
{
foreach (var result in results)
{
Console.WriteLine("{0}, {1}", result.Key, result.Value);
}
}
Console.WriteLine("Using multidimensional array");
for (int row = 0; row < rowIndex; row++)
{
Console.WriteLine("{0}, {1}", results2[row, 0], results2[row, 1]);
}
But multidimensional array is not suitable data structure for this task. (You can see code with array looks terrible). Data structure that you need is called tuple and the definition for results can look like var results3 = new List<Tuple<string, string>>();
Additional note - you not need using .Any() with foreach statement. foreach is not executed for empty collections.
Good luck with learning C#!
I used Extension method to achieve the desired result.
public static string[,] FoodPreferenceWithDimensionalArray()
{
var foodPair = new Dictionary<string, string>
{
{"Pizza", "Italian"},
{"Curry", "Indian"},
{"Masala", "Indian"}
};
var teamPreference = new Dictionary<string, string>
{
{"Jose", "Italian" },
{"John", "Indian" },
{"Sarah", "Thai" },
{"Mary", "*" }
};
var results = new List<KeyValuePair<string, string>>();
foreach (var teamMember in teamPreference)
{
switch (teamMember.Key)
{
case "Jose":
var italianDish = foodPair.FirstOrDefault(x => x.Value == "Italian").Key;
results.Add(new KeyValuePair<string, string>(teamMember.Key, italianDish));
break;
case "John":
var indianDish = foodPair.Where(x => x.Value == "Indian");
if (indianDish.Any())
{
results.AddRange(indianDish.Select(dish => new KeyValuePair<string, string>(teamMember.Key, dish.Key)));
}
break;
case "Sarah":
var thaiDish = foodPair.FirstOrDefault(x => x.Value == "Thai").Key;
if (!string.IsNullOrEmpty(thaiDish))
{
results.Add(new KeyValuePair<string, string>(teamMember.Key, thaiDish));
}
break;
case "Mary":
if (teamMember.Value == "*")
{
var everything = foodPair.Keys.ToList();
if (everything.Any())
{
results.AddRange(everything.Select(food => new KeyValuePair<string, string>(teamMember.Key, food)));
}
}
break;
}
}
var resultIn2DArray = results.To2DArray();
return resultIn2DArray;
}
// Created extension to convert List to String[,]
public static class Extension
{
public static string[,] To2DArray<T>(this List<T> list)
{
if (list.Count == 0)
{
throw new ArgumentException("The list must have non-zero dimensions.");
}
var result = new string[list.Count, list.Count];
for (var i = 0; i < list.Count; i++)
{
// This is set to 0 since I know the output but will work on this to make it dynamic.
result[0, i] = list[i].ToString();
}
return result;
}
}
Thank you all for your input.
My array:
string[] name = "a,b,c,d".Split(',');//key
string[] path = "w,x,y,z".Split(',');//value
List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
I try to assign a value like this.
foreach (string s in name)
{
foreach (string sp in path)
{
list.Add(new KeyValuePair<string, string>(s, sp));
}
}
But my logic is fail. What is a proper way to assign a KeyValue pair from two arrays?
Expected outcome.
a-w
b-x
c-y
d-z
Try using:
string[] names = "a,b,c,d".Split(','); //key
string[] paths = "w,x,y,z".Split(','); //value
var namesAndPaths = names.Zip(paths, (name, path) => new KeyValuePair<string,string>(name, path));
You must use the same loop for both arrays (or use the LINQ solutions proposed in other answers):
string[] name = "a,b,c,d".Split(','); // Key
string[] path = "w,x,y,z".Split(','); // Value
List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
for (int i = 0; i < name.Length, i++)
{
if (i == path.Length) // In case both arrays are not the same length
{
break;
}
list.Add(new KeyValuePair<string, string>(name[i], path[i]));
}
If you are sure that both arrays are equal length, you can do:
for (var i = 0; i < name.Length; ++i) {
list.Add(new KeyValuePair<string, string>(name[i], path[i]));
}
Assuming both arrays will be of same length you can do this -
for(int i=0; i<name.Length; i++)
{
list.Add(new KeyValuePair<string, string>(name[i], path[i]));
}
string[] name = "a,b,c,d".Split(','); //key
string[] path = "w,x,y,z".Split(','); //value
List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
for (int i = 0; i < name.Length; i++)
{
for (int j = 0; j < path.Length; j++)
{
if (i == j)
{
list.Add(new KeyValuePair<string, string>(name[i], path[j]));
}
}
}
You could do this using LINQ:
var mergedKeyValues = name.Select((n,i) => new KeyValuePair<string,string>(n,path[i]))
.ToList();
Output
[a, w]
,
[b, x]
,
[c, y]
,
[d, z]
Check out this demo.
Use a LINQ one-liner:
var d = name.Select((n, idx) => new { Name = n, Index = idx })
.ToDictionary(k => k.Name, v => path[v.Index]);
The key here is to use the index from the Select method to determine the index to use in the other array.
I have the two lists:
List<string> keys = new List<string>()
{
"REPORTMONTH",
"CONTRACT", "DATE", "AMOUNT",
"CONTRACT", "DATE", "AMOUNT"
};
List<string> values = new List<string>()
{
"01",
"ABC123", "01022014", "300.00",
"DEF345", "03042014", "400.00"
};
The first list represents keywords which can have certain repetitions. The second list contains values associated with the keys in the first list (by index). The result output should be of type List<Dictionary<string, string>> and contain:
1st dictionary
key value
"REPORTMONTH" "01"
"CONTRACT" "ABC123"
"DATE" "01022014"
"AMOUNT" "300.00"
2nd dictionary
key value
"REPORTMONTH" "01"
"CONTRACT" "DEF345"
"DATE" "03042014"
"AMOUNT" "400.00"
I.e. the keys that do not repeat should present in both dictionaries, the rest should be splitted into dictionaries with associated values.
Note, there can be no repeptitions at all, or more than 2.
Sorry, I cannot show my attempts for this question, because I'm not sure how to start. Maybe using LINQ and grouping can solve the problem?
Thank you.
You could do this in a way that does not look that elegant, requiring some loops. Note that this will also work if there are more than 2 dictionaries.
public static void Main(params string[] args)
{
List<string> keys = new List<string>() {
"REPORTMONTH",
"CONTRACT", "DATE", "AMOUNT",
"CONTRACT", "DATE", "AMOUNT"
};
List<string> values = new List<string>() {
"01",
"ABC123", "01022014", "300.00",
"DEF345", "03042014", "400.00"
};
var pairs = keys.Select((key, ndx) => new { Key = key, Value = values[ndx] });
var groups = pairs.GroupBy(e => e.Key)
.ToDictionary(g => g.Key, g => g.Select(kvp => kvp.Value).ToArray());
var dictionaries = new Dictionary<string, string>[groups.Max(g => g.Value.Length)];
for (var i = 0; i < dictionaries.Length; i++)
{
dictionaries[i] = new Dictionary<string,string>();
foreach (var g in groups)
{
if (g.Value.Length == 1)
dictionaries[i][g.Key] = g.Value[0];
else if (g.Value.Length > i)
dictionaries[i][g.Key] = g.Value[i];
}
}
// print content
for (var i = 0; i < dictionaries.Length; i++)
{
Console.WriteLine("Dictionary {0}:", i + 1);
Console.WriteLine(string.Join(Environment.NewLine, dictionaries[i].Select(e => string.Format("{0} = {1}", e.Key, e.Value))));
Console.WriteLine();
}
Console.ReadLine();
}
You can do this by first using Enumerable.Zip() to get a sequence of key/value pairs and convert the list into a lookup, then process that list into two dictionaries:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication2
{
class Program
{
static void Main()
{
List<string> keys = new List<string>
{
"REPORTMONTH",
"CONTRACT", "DATE", "AMOUNT",
"CONTRACT", "DATE", "AMOUNT"
};
List<string> values = new List<string>
{
"01",
"ABC123", "01022014", "300.00",
"DEF345", "03042014", "400.00"
};
var combined = Enumerable.Zip(
keys, values, (key, value) => new { Key = key, Value = value})
.ToLookup(entry => entry.Key);
var dicts = new []
{
new Dictionary<string, string>(),
new Dictionary<string, string>()
};
foreach (var items in combined)
{
int count = 0;
string lastKey = null;
foreach (var item in items.Take(2))
{
dicts[count++][item.Key] = item.Value;
lastKey = item.Key;
}
if (count == 1)
dicts[1][lastKey] = dicts[0][lastKey];
}
dump("1st dictionary", dicts[0]);
dump("2nd dictionary", dicts[1]);
}
static void dump(string title, Dictionary<string, string> data)
{
Console.WriteLine(title);
foreach (var item in data)
Console.WriteLine("Key: {0}, Value: {1}", item.Key, item.Value);
Console.WriteLine();
}
}
}