1

I'm reading a CSV file and am basically trying to use the headers to determine the ordinal position of the values in the file, though the last part is giving me some trouble. The following is what I have so far:

private static IEnumerable<Cow> ReadCowStream(Stream source)
    {
        bool isHeader = true;
        var cows = new List<Cow>();

        using (var reader = new StreamReader(source))
        {
            while (!reader.EndOfStream)
            {
                var line = reader.ReadLine();
                if (line != null)
                {
                    var values = line.Split(',');

                    if (isHeader && values.Contains("Weight") && values.Contains("Age"))
                    {
                        isHeader = false;
                    }
                    else
                    {
                        cows.Add(new Cow(
                            weight: values[0],
                            age: values[1]));
                    }
                }
            }
        }

        return animals;
    }

Example CSV:

Weight,Age
300,10
319,11
100,1
370,9

In this case the output would be a List<Cow> with the first entry having values "Weight": "300" and "Age": "10" obviously, but what if "Weight" and "Age" are reversed? Then I'll assign the wrong values to the wrong variables.

Basically, I want to use the headers for determining whether to put values[0] into weight or age etc., as I assume I can't be guaranteed which comes first in the CSV I'm reading.

2
  • you could just check what comes first, i.e if(header[0] == 'Weight')[...] else [...] that would be the easiest i'd say. Commented May 29, 2018 at 11:01
  • 2
    Consider using CsvHelper Commented May 29, 2018 at 11:03

3 Answers 3

5

Using a library like CsvHelper, the values can be extracted based on the header name rather than index.

private static IEnumerable<Cow> ReadCowStream(Stream source) {
    var cows = new List<Cow>();
    using (var reader = new StreamReader(source)) {
        var csv = new CsvReader(reader);
        csv.Read();
        csv.ReadHeader();
        while (csv.Read()) {
            cows.Add(new Cow(weight: csv["Weight"], age: csv["Age"]));
        }
    }
    return cows;
}

So now it does not matter which header comes first in the CSV being read.

The library allows for strongly typed parsing.

If Cow is defined with a default constructor and have the properties in the appropriate typed

public class Cow {
    public int Age { get; set; }
    public int Weight { get; set; }
}

ReadCowStream could be simplified to

private static IEnumerable<Cow> ReadCowStream(Stream source) {
    using (var reader = new StreamReader(source)) {
        var csv = new CsvReader(reader);
        return csv.GetRecords<Cow>().ToList();
    }
}

the CSV reader will parse the lines, create instances and assign the values by matching the headers to the property names.

Sign up to request clarification or add additional context in comments.

2 Comments

That is a cool and elegant solution; first time I'm using CsvHelper.
@Khaine775 added some additional details.
2

You could store the header indices for example:

int weightIndex = Array.FindIndex(values, v => v == "Weight");
int ageIndex = Array.FindIndex(values, v => v == "Age");

Then access the values as follows:

cows.Add(new Cow(
    weight: values[weightIndex],
    age: values[ageIndex]));

Comments

0

With Cinchoo ETL - an open source library, you can do the csv parsing easily with few lines of code

public class Cow
{
    public int Age { get; set; }
    public int Weight { get; set; }
}

static void Main(string[] args)
{
    string csv = @"Weight,Age
    300,10
    319,11
    100,1
    370,9";

    foreach (Cow rec in ChoCSVReader<Cow>.LoadText(csv).WithFirstLineHeader())
    {
        Console.WriteLine($"Age: {rec.Age}, Weight: {rec.Weight}");
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.