Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using csvHelper to read cell content into List or Array

Tags:

c#

csvhelper

I have a csv file of the type:

name,numbersA,numbersB
Bob,"1,2,3,4","6,7,8,9"
Brabra,"9,3","4,8,5,7,2"

So arrays of ints are given by the numbers in between the " ".

I want to map that to the following class

    public class Names
    {
        [Name("name")]
        public string Name { get; set; }

        [Name("numbersA")]
        public List<int> NumbersA{ get; set; }

        [Name("numbersB")]
        public List<int> NumbersB{ get; set; }

    }

I don't specifically mind if the NumbersA/B is of type int[] or List. So far I managed to read the data by specifying the type of NumbersA/B as string and that works correctly (I get the string between the " "). Can this be done automatically in csvHelper or do I have to parse the string myself later on.

void Main()
{
    using (var reader = new StreamReader("path\\to\\file.csv"))
    using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
    {
        var records = csv.GetRecords<Names>();
        List<Names> NameList = records.ToList();
    }
}

Any help would be very much appreciated.

SOLUTION

Credit goes to @Oguz Ozgul (see below). I made a couple of minor changes.


public class Names
{
    [Name("name")]
    public string Name { get; set; }

    [Name("numbersA")]
    [TypeConverter(typeof(ToIntArrayConverter))]
    public List<int> NumbersA{ get; set; }

    [Name("numbersB")]
    [TypeConverter(typeof(ToIntArrayConverter))]
    public List<int> NumbersB{ get; set; }

}

public class ToIntArrayConverter : TypeConverter
{
    public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
    {
        if (text == "") return new List<int>();
        string[] allElements = text.Split(',');
        int[] elementsAsInteger = allElements.Select(s => int.Parse(s)).ToArray();
        return new List<int>(elementsAsInteger);
    }

    public override string ConvertToString(object value, IWriterRow row, MemberMapData memberMapData)
    {
        return string.Join(",", ((List<int>)value).ToArray());
    }
}

like image 740
Eule Avatar asked Oct 20 '25 18:10

Eule


1 Answers

You can implement a custom type converter and use it during conversion (both directions) for your two properties.

The TypeConverter class is under namespace CsvHelper.TypeConversion

The TypeConverterAttribute is under namespace CsvHelper.Configuration.Attributes

    public class ToIntArrayConverter : TypeConverter
    {
        public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
        {
            string[] allElements = text.Split(',');
            int[] elementsAsInteger = allElements.Select(s => int.Parse(s)).ToArray();
            return new List<int>(elementsAsInteger);
        }

        public override string ConvertToString(object value, IWriterRow row, MemberMapData memberMapData)
        {
            return string.Join(',', ((List<int>)value).ToArray());
        }
    }

To use this converter, simply add the following TypeConverterAttribute annotations on top of your properties:

    public class Names
    {
        [Name("name")]
        public string Name { get; set; }

        [Name("numbersA")]
        [TypeConverter(typeof(ToIntArrayConverter))]
        public List<int> NumbersA { get; set; }

        [Name("numbersB")]
        [TypeConverter(typeof(ToIntArrayConverter))]
        public List<int> NumbersB { get; set; }
    }
like image 188
Oguz Ozgul Avatar answered Oct 22 '25 09:10

Oguz Ozgul



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!