【发布时间】:2019-10-01 21:32:10
【问题描述】:
我有一个类对象列表,其中又包含另一个类对象的列表。它们看起来像这样:
public class Column
{
public string ColName { get; set; }
public List<Item> ItemList { get; set; }
}
public class Item
{
public DateTime TimeStamp { get; set; }
public double Value { get; set; }
}
它们有两个重要的属性:
- 所有列中
List<Item> ItemList的Length将相同。不过,直到运行时我才知道这个长度是多少。 - 每列中
TimeStamp的实际值将相同。换句话说,每一列中的TimeStamp列表将是相同的。
如果您查看我为创建Column 对象列表而编写的以下模拟函数,您将获得清晰的画面。这是对我的实际数据(我从程序的其他地方获得)的准确描述:
private static List<Column> GetColumns()
{
var dt1 = DateTime.Now;
var dt2 = dt1.AddSeconds(1);
var dt3 = dt2.AddSeconds(1);
var dt4 = dt3.AddSeconds(1);
var col1 = new Column()
{
ColName = "ABC",
ItemList = new List<Item>
{
new Item() { TimeStamp = dt1, Value = 1 },
new Item() { TimeStamp = dt2, Value = 2 },
new Item() { TimeStamp = dt3, Value = 3 },
new Item() { TimeStamp = dt4, Value = 4 }
}
};
var col2 = new Column()
{
ColName = "XYZ",
ItemList = new List<Item>
{
new Item() { TimeStamp = dt1, Value = 4 },
new Item() { TimeStamp = dt2, Value = 3 },
new Item() { TimeStamp = dt3, Value = 2 },
new Item() { TimeStamp = dt4, Value = 1 }
}
};
var col3 = new Column()
{
ColName = "KLM",
ItemList = new List<Item>
{
new Item() { TimeStamp = dt1, Value = 1 },
new Item() { TimeStamp = dt2, Value = 2 },
new Item() { TimeStamp = dt3, Value = 4 },
new Item() { TimeStamp = dt4, Value = 8 }
}
};
var list = new List<Column>
{
col1,
col2,
col3,
};
return list;
}
一个重要的注意事项是直到运行时我才知道List<Column> 的长度,直到运行时我也不知道它们内部的ItemList 的长度。此外,直到运行时我才会知道每列的名称。现在我的目标是将这些信息写入CSV 文件,格式如下。
我觉得dynamic 是这里的路,所以我从这个开始:
var columns = GetColumns();
var timeStamps = columns.First().ItemList.Select(x => x.TimeStamp).ToList();
var writeList = new List<dynamic>();
for (int i = 0; i < timeStamps.Count; i++)
{
dynamic csvItem = new ExpandoObject();
csvItem.TimeStamp = timeStamps[i];
// How to get columns?
writeList.Add(csvItem);
}
using (var writer = new StreamWriter("output.csv"))
{
using (var csv = new CsvHelper.CsvWriter(writer))
{
csv.WriteRecords(writeList);
}
}
这是一个开始,但由于我不知道我将拥有的列数和它们的名称,我不知道如何从这里开始。在这里使用dynamic 不是一个选项吗?
或者,我可以完全放弃使用CSVHelper,而从头开始编写如下内容,但这有点混乱。我正在遍历列列表两次,总共三个循环。如果可能的话,我正在寻找更优雅的解决方案。
var columns = GetColumns();
var timeStamps = columns.First().ItemList.Select(x => x.TimeStamp).ToList();
var headers = "TimeStamp";
foreach (var col in columns)
{
headers += "," + col.ColName;
}
using (var fs = new FileStream("output.csv", FileMode.Create, FileAccess.Write))
{
using (var sw = new StreamWriter(fs))
{
sw.WriteLine(headers);
for (int i = 0; i < timeStamps.Count; i++)
{
var line = timeStamps[i].ToString("yyyy/MM/dd HH:mm:ss");
foreach (var col in columns)
{
line += "," + col.ItemList[i].Value;
}
sw.WriteLine(line);
}
}
}
【问题讨论】:
-
为什么不使用
StringBuilder创建整个 csv 结构并将其保存为 csv?它会比第二种方法快得多。至于 csvHelper,我什至不会为这样简单的事情添加 nuget 依赖项。 -
@KosalaW 你有样品让我开始吗?我使用
CSVHelper的原因是我们的项目已经在其他地方使用它进行许多其他 CSV 操作,所以我想坚持使用它。
标签: c# csv dynamic csvhelper expandoobject