I have a list of class objects, which in turn contain a list of another class objects. They look like this:
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; }
}
They have two important properties:
Length
of List<Item> ItemList
in all columns will be the same. I won't know what that length is until run-time though.TimeStamp
in each column will be the same. In other words, the TimeStamp
list in each column will be identical.If you look at the following mock function that I wrote to create a list of Column
objects you'll get a clear picture. This is an accurate description of what my actual data (which I get from somewhere else in the program) will look like:
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;
}
An important note is that I will not know the length of List<Column>
until run-time, nor will I know the length of ItemList
inside them until run-time. Furthermore, I will not know the names of each column until run-time. Now my goal is to write this information into a CSV
file, of the following format.
I feel like dynamic
is the way to go here, so I started with this:
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);
}
}
This is a start, but since I don't know the number of columns I will have and the names of them, I'm not sure how to proceed from here. Is using dynamic
not an option here?
Alternatively I could forgo using CSVHelper
at all, and write something from scratch like the following, but it's a bit messy. I'm iterating through the column list twice, and three loops in total. I'm looking for a more elegant solution, if possible.
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);
}
}
}
This is probably the best you can do with CsvHelper for your requirements.
using (var writer = new StreamWriter("output.csv"))
{
using (var csv = new CsvHelper.CsvWriter(writer))
{
var columns = GetColumns();
// Write header
csv.WriteField("TimeStamp");
foreach (var column in columns)
{
csv.WriteField(column.ColName);
}
csv.NextRecord();
// Write rows
for (int i = 0; i < columns[0].ItemList.Count; i++)
{
csv.WriteField(columns[0].ItemList[i].TimeStamp.ToString("yyyy/MM/dd HH:mm:ss"));
foreach (var column in columns)
{
csv.WriteField(column.ItemList[i].Value);
}
csv.NextRecord();
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With