У меня есть список объектов класса, который в свою очередь содержит список объектов другого класса. Они выглядят так:
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; }
}
У них есть два важных свойства:
-
Length
из List<Item> ItemList
во всех столбцах будет одинаковым. Я не буду знать, что это за длина до времени выполнения. - Фактические значения
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);
}
}
}