如何将CsvHelper读取的List转换为List<Dictionary<string,object>>
问题描述
已有含重复X (mm)、Y (mm)列的CSV文件,通过CsvHelper成功读取为List<SicaGraphData>集合。现需将该集合转换为List<Dictionary<string, object>>格式,使数据呈现类似Y (mm): -61.232543的键值对形式,以便后续转为DataTable存入MongoDB。
CSV示例
23.75,-71.14026637566099,23.26,-68.14,X (mm),Y (mm),X (mm),Y (mm),X (mm),Y (mm) 75.0,0.0,72.0,0.0,-70.8744,-11.0272,-62.1812,-22.0121,1.1013,5.3621 ...
当前读取代码
class CsvHelperTester { static void Main(string[] args) { var config = new CsvConfiguration(CultureInfo.InvariantCulture) { HasHeaderRecord = false, MissingFieldFound = null, ShouldSkipRecord = args => args.Row.Parser.Record.All(String.IsNullOrEmpty) }; using (var reader = new StreamReader("C:\\Users\\eyoung\\Desktop\\parse test files\\Data.csv")) using (var csv = new CsvReader(reader, config)) { var sicaGraphDataList = new List<SicaGraphData>(); while (csv.Read()) { sicaGraphDataList.Add(csv.GetRecord<SicaGraphData>()); } // 转换逻辑写在此处 } } public class SicaGraphData { public string Value1 { get; set; } public string Value2 { get; set; } public string Value3 { get; set; } public string Value4 { get; set; } [Name("X (mm)")] public string X { get; set; } [Name("Y (mm)")] public string Y { get; set; } [Name("X2 (mm)")] public string X2 { get; set; } [Name("Y2 (mm)")] public string Y2 { get; set; } [Name("X3 (mm)")] public string X3 { get; set; } [Name("Y3 (mm)")] public string Y3 { get; set; } } }
解决方案
方案1:每行拆分为多个字典(每组X/Y独立成条)
如果需要把每行中的三组X (mm)/Y (mm)分别作为独立的字典对象(每个字典包含前4个通用值+一组X/Y),可按以下代码实现:
var dictList = new List<Dictionary<string, object>>(); foreach (var data in sicaGraphDataList) { // 提取前4列通用值 var baseDict = new Dictionary<string, object> { {"Value1", Convert.ToDouble(data.Value1)}, {"Value2", Convert.ToDouble(data.Value2)}, {"Value3", Convert.ToDouble(data.Value3)}, {"Value4", Convert.ToDouble(data.Value4)} }; // 第一组X/Y var dict1 = new Dictionary<string, object>(baseDict) { {"X (mm)", Convert.ToDouble(data.X)}, {"Y (mm)", Convert.ToDouble(data.Y)} }; dictList.Add(dict1); // 第二组X/Y var dict2 = new Dictionary<string, object>(baseDict) { {"X (mm)", Convert.ToDouble(data.X2)}, {"Y (mm)", Convert.ToDouble(data.Y2)} }; dictList.Add(dict2); // 第三组X/Y var dict3 = new Dictionary<string, object>(baseDict) { {"X (mm)", Convert.ToDouble(data.X3)}, {"Y (mm)", Convert.ToDouble(data.Y3)} }; dictList.Add(dict3); }
说明:
- 将字符串类型的数值转为
double,更适配MongoDB的数值存储需求 - 每行数据生成3个字典对象,完整保留每组X/Y的独立数据关系
方案2:重复X/Y转为数组(每行对应一个字典)
如果希望每行数据对应一个字典,重复的X (mm)/Y (mm)以数组形式存储,可按以下代码实现:
var dictList = new List<Dictionary<string, object>>(); foreach (var data in sicaGraphDataList) { var dict = new Dictionary<string, object> { {"Value1", Convert.ToDouble(data.Value1)}, {"Value2", Convert.ToDouble(data.Value2)}, {"Value3", Convert.ToDouble(data.Value3)}, {"Value4", Convert.ToDouble(data.Value4)}, {"X (mm)", new[] { Convert.ToDouble(data.X), Convert.ToDouble(data.X2), Convert.ToDouble(data.X3) }}, {"Y (mm)", new[] { Convert.ToDouble(data.Y), Convert.ToDouble(data.Y2), Convert.ToDouble(data.Y3) }} }; dictList.Add(dict); }
说明:
- 重复列的值封装为
double[]数组,保证字典键的唯一性 - 适合需要保留整行数据结构的场景,MongoDB原生支持数组类型存储
方案3:反射自动映射(适配扩展X/Y组)
如果后续可能新增更多X/Y组,可通过反射自动识别属性,避免硬编码:
var dictList = new List<Dictionary<string, object>>(); var props = typeof(SicaGraphData).GetProperties(); foreach (var data in sicaGraphDataList) { // 自动提取Value开头的通用属性 var baseDict = props .Where(p => p.Name.StartsWith("Value")) .ToDictionary(p => p.Name, p => (object)Convert.ToDouble(p.GetValue(data))); // 自动分组X/Y属性 var xProps = props.Where(p => p.Name.StartsWith("X")).OrderBy(p => p.Name).ToList(); var yProps = props.Where(p => p.Name.StartsWith("Y")).OrderBy(p => p.Name).ToList(); for (int i = 0; i < xProps.Count; i++) { var dict = new Dictionary<string, object>(baseDict) { {"X (mm)", Convert.ToDouble(xProps[i].GetValue(data))}, {"Y (mm)", Convert.ToDouble(yProps[i].GetValue(data))} }; dictList.Add(dict); } }
说明:
- 通过反射自动识别属性,新增X/Y组时无需修改转换逻辑
- 按属性名称排序,确保X/Y组的对应关系准确
内容的提问来源于stack exchange,提问作者Kevin Jablowski
相关产品推荐
相关产品推荐

