Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Read CSV to list of objects [duplicate]

Tags:

c#

csv

I have a CSV file with a listing of varied data(datetime, decimal). Sample line from CSV:

Date,Open,High,Low,Close,Volume,Adj Close  //I need to skip this first line as well 2012-11-01,77.60,78.12,77.37,78.05,186200,78.05 

I have a list of objects created that I want to read each of the lines into. The constructor for the objects is below, each of the fields from each CSV line is used and assigned here.

    public DailyValues(DateTime date, decimal open, decimal high, decimal low,         decimal close, decimal volume, decimal adjClose)         : this()     {         Date = date;         Open = open;         High = high;         Low = low;         Close = close;         Volume = volume;         AdjClose = adjClose;     }      List<DailyValues> values = new List<DailyValues>(); 

Is there an easy way to read each line of the CSV into my list values and appropriately assign each attribute (i.e. date, open, high)?

like image 879
user3066571 Avatar asked Nov 06 '14 22:11

user3066571


1 Answers

Why not just parse these explicitly? You have a limited number of properties, so it's not very difficult. Instead of using a constructor requiring many arguments, I used a static method that returns a new DailyValues instance as it's return type. This is similar to DateTime.FromBinary etc.

using System; using System.Collections.Generic; using System.Linq; using System.IO;  namespace CsvDemo {     class Program     {         static void Main(string[] args)         {             List<DailyValues> values = File.ReadAllLines("C:\\Users\\Josh\\Sample.csv")                                            .Skip(1)                                            .Select(v => DailyValues.FromCsv(v))                                            .ToList();         }     }      class DailyValues     {         DateTime Date;         decimal Open;         decimal High;         decimal Low;         decimal Close;         decimal Volume;         decimal AdjClose;          public static DailyValues FromCsv(string csvLine)         {             string[] values = csvLine.Split(',');             DailyValues dailyValues = new DailyValues();             dailyValues.Date = Convert.ToDateTime(values[0]);             dailyValues.Open = Convert.ToDecimal(values[1]);             dailyValues.High = Convert.ToDecimal(values[2]);             dailyValues.Low = Convert.ToDecimal(values[3]);             dailyValues.Close = Convert.ToDecimal(values[4]);             dailyValues.Volume = Convert.ToDecimal(values[5]);             dailyValues.AdjClose = Convert.ToDecimal(values[6]);             return dailyValues;         }     } } 

Of course, you can still add a default constructor, and you will want to add exception handling in case the parsing fails (you can also use TryParse for that).

  • The File.ReadAllLines reads all lines from the CSV file into a string array.
  • The .Skip(1) skips the header line.
  • The .Select(v => DailyValues.FromCsv(v)) uses Linq to select each line and create a new DailyValues instance using the FromCsv method. This creates a System.Collections.Generic.IEnumerable<CsvDemo.DailyValues> type.
  • Finally, the .ToList() convers the IEnumerable to a List to match the type you want.

Instead of using Linq you could have simply used a foreach loop to add each DailyValues instance to your list.

like image 179
grovesNL Avatar answered Sep 22 '22 09:09

grovesNL