如何将 C# 中的 Dictionary <string,List<string>> 转换为带有键作为标题的 csv?
Posted
技术标签:
【中文标题】如何将 C# 中的 Dictionary <string,List<string>> 转换为带有键作为标题的 csv?【英文标题】:How to convert Dictionary <string,List<string>> in C# to csv with keys as headers? 【发布时间】:2021-05-06 23:29:29 【问题描述】:我有一个像这样的字典:
key1 : List1 value1a, value2a,
key2 : List2 value1b, value2b,
...
我怎样才能把它变成一个 csv 看起来像:
key1,key2
value1a,value1b
value2a,value2b
...
我已尝试先将其转换为 DataTable,但在我的 Linq 基础知识方面遇到了问题。
dataTable.Columns.AddRange(dataDictionary
.Keys
.Select(x => new DataColumn(x, dataDictionary[x])).ToArray());
dataDictionary[x] List<string> can't be converted to System.Type.
我也尝试过 direct-to-csv 路由,但我再次无法记住如何正确访问 LINQ 中列表的值,并且无法将键作为标题并将列表放入列:
File.WriteAllLines($@"args[3]\args[0]_args[1]_args[2].csv",
dataDictionary.Select(x => x.Key + ";" + x.Value + ";"));
【问题讨论】:
如果您选择将字段放入类或结构中,您可能会发现CSVHelper 很有用。但是,它似乎是针对具有硬编码列的。 【参考方案1】:如果您正在寻找 csv(例如 csv 文件),而不是 DataTable
,您可以直接实现 csv 行生成器:
代码:
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] : "")));
演示:
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);
结果:
column1,column2,column3,column4
C1_A,C2_A,,C4_A
C1_B,C2_B,,
,C2_C,,
在你的情况下(将 csv 写入 文件)你可以把它写成
File.WriteAllLines(@"c:\demo.csv", ToCsv(myDictionary));
【讨论】:
太棒了,我以前什至没见过'yield'。感谢分享。【参考方案2】:首先,你遇到了错误
dataDictionary[x] List<string> can't be converted to System.Type.
因为,DataColumn
有多个重载的构造函数,而您尝试在下面调用,它无法将 List<string>
转换为 Type
。
public DataColumn(string columnName, Type dataType)
其次,下面是假设每个List<string>
具有相同长度的代码。
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());
结果:
key1,key2
value1a,value1b
value2a,value2b
【讨论】:
嘿 Nayan,这真的很棒。我认为这只是添加与列一样多的行,但这仅适用于这个 2x2 示例。你可以修改 for 循环以根据列表长度填充行吗? @MarkMcGown 如果键的数量与列表长度不同,您如何获得 CSV? @NetMage 列表长度将成为该列表的键是标题的列的行数。 @MarkMcGown 很抱歉,我觉得这不太好理解。也许在您的问题中添加更多示例。在 CSV 文件中,所有列的长度都相同 - 在 CSV 文件中,# 列等于键的数量。【参考方案3】:如果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])));
【讨论】:
以上是关于如何将 C# 中的 Dictionary <string,List<string>> 转换为带有键作为标题的 csv?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 C# 中将 Dictionary<string, object> 转换为 Dictionary<string, string>