I have a Dictionary like:
{
key1 : List1 {value1a, value2a},
key2 : List2 {value1b, value2b},
...
}
How can I get this into a csv that looks like:
key1,key2
value1a,value1b
value2a,value2b
...
I've tried first converting this to a DataTable but am having trouble with my Linq fundamentals.
dataTable.Columns.AddRange(dataDictionary
.Keys
.Select(x => new DataColumn(x, dataDictionary[x])).ToArray());
dataDictionary[x] List<string> can't be converted to System.Type.
I've also tried the direct-to-csv route but again I am having trouble remembering how to access the values of the list in LINQ correctly and can't get the keys as headers and the lists into columns:
File.WriteAllLines($@"{args[3]}\{args[0]}_{args[1]}_{args[2]}.csv",
dataDictionary.Select(x => x.Key + ";" + x.Value + ";"));
If you are looking for csv (say, csv file), not DataTable
you can implement csv lines generator straightforward:
Code:
using System.Linq;
...
private static IEnumerable<string> ToCsv(Dictionary<string, List<String>> data) {
// Quotation if required: 123,45 -> "123,45"; a"bc -> "a""bc"
string Quote(string value) => string.IsNullOrEmpty(value)
? "" : value.Contains(',') || value.Contains('"')
? "\"" + value.Replace("\"", "\"\'") + "\""
: value;
int rowCount = data.Max(pair => pair.Value.Count);
// Captions
yield return string.Join(",", data.Select(pair => Quote(pair.Key)));
// Rows one after one
for (int r = 0; r < rowCount; ++r)
yield return string.Join(",", data
.Select(pair => Quote(r < pair.Value.Count ? pair.Value[r] : "")));
}
Demo:
Dictionary<string, List<string>> data = new Dictionary<string, List<string>>() {
{ "column1", new List<string>() { "C1_A", "C1_B"} },
{ "column2", new List<string>() { "C2_A", "C2_B", "C2_C"} },
{ "column3", new List<string>() { } },
{ "column4", new List<string>() { "C4_A" } },
};
// Generate all lines of the csv and combine them with \r\n:
string csvText = string.Join(Environment.NewLine, ToCsv(data));
Console.Write(csvText);
Outcome:
column1,column2,column3,column4
C1_A,C2_A,,C4_A
C1_B,C2_B,,
,C2_C,,
In your case (writing csv into a file ) you can put it as
File.WriteAllLines(@"c:\demo.csv", ToCsv(myDictionary));
Firstly, you are getting below error
dataDictionary[x] List<string> can't be converted to System.Type.
because, DataColumn
have multiple overloaded constructor and you are trying call below, which is unable to cast List<string>
to Type
.
public DataColumn(string columnName, Type dataType)
Second, below is the code with assuming that every List<string>
have same length.
using System.IO;
using System.Linq;
using System.Text;
using System;
using System.Collections.Generic;
using System.Data;
class Program
{
static void Main(string[] args)
{
Dictionary<string, List<string>> values = new Dictionary<string, List<string>>();
values.Add("key1", new List<string>() { "value1a", "value2a" });
values.Add("key2", new List<string>() { "value1b", "value2b" });
DataTable dataTable = new DataTable();
dataTable.Columns.AddRange(values.Keys.Select(x => new DataColumn(x)).ToArray());
var totalColumns = dataTable.Columns.Count;
for(int i = 0; i < totalColumns; i++)
{
DataRow dataRow = dataTable.NewRow();
int fieldNumber = 0;
foreach(var item in values)
{
dataRow[fieldNumber] = values[item.Key][i];
fieldNumber++;
}
dataTable.Rows.Add(dataRow);
}
dataTable.WriteToCsvFile("D://Test.csv");
}
}
public static class Extension
{
public static void WriteToCsvFile(this DataTable dataTable, string filePath)
{
var content = dataTable.GenerateCsvBytes();
File.WriteAllBytes(filePath, content);
}
public static byte[] GenerateCsvBytes(this DataTable dataTable)
{
StringBuilder fileContent = new StringBuilder();
foreach (var col in dataTable.Columns)
{
fileContent.Append(col.ToString() + ",");
}
fileContent.Replace(",", Environment.NewLine, fileContent.Length - 1, 1);
foreach (DataRow dr in dataTable.Rows)
{
foreach (var column in dr.ItemArray)
{
fileContent.Append("\"" + column.ToString() + "\",");
}
fileContent.Replace(",", Environment.NewLine, fileContent.Length - 1, 1);
}
return Encoding.ASCII.GetBytes(fileContent.ToString());
}
}
Result:
key1,key2
value1a,value1b
value2a,value2b
This will fail if data.Keys.Count
!= data.Values[0].Count
.
var keys = data.Keys;
Console.WriteLine(String.Join(",", keys));
for (int j1 = 0; j1 < keys.Count; ++j1)
Console.WriteLine(String.Join(",", data.Values.Select(v => v[j1])));
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.