【问题标题】:CsvHelper - read in multiple columns to a single listCsvHelper - 将多列读入单个列表
【发布时间】:2013-06-27 21:23:20
【问题描述】:

我正在使用CSVHelper 读取大量数据

我想知道是否可以读取最后的 n 列并将它们转换为列表

"Name","LastName","Attribute1","Attribute2","Attribute3"

然后将数据塑造成这样的东西

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public IList<string> Attributes { get; set; }
}

我希望一步完成,我确信我可以有一个中间步骤,在其中放入一个具有匹配属性属性的对象,但最好一次性完成

【问题讨论】:

    标签: c# csvhelper


    【解决方案1】:

    这可以作为映射器。

    public sealed class PersonMap : CsvClassMap<Person>
    {
        private List<string> attributeColumns = 
            new List<string> { "Attribute1", "Attribute2", "Attribute3" };
    
        public override void CreateMap()
        {
            Map(m => m.FirstName).Name("FirstName").Index(0);
            Map(m => m.LastName).Name("LastName").Index(1);
            Map(m => m.Attributes).ConvertUsing(row =>
                attributeColumns
                    .Select(column => row.GetField<string>(column))
                    .Where(value => String.IsNullOrWhiteSpace(value) == false)
                );
        }
    }
    

    那么你只需要这样的东西

    using (var reader = new CsvReader(new StreamReader(filePath)))
    {
        reader.Configuration.RegisterClassMap<PersonMap>();
        while (reader.Read())
        {
            var card = reader.GetRecord<Person>();
        }
    }
    

    【讨论】:

    • 我应该如何从“Person”对象中动态获得“attributeColumns”而不是硬编码随机字符串?
    【解决方案2】:

    版本 3 支持读取和写入 IEnumerable 属性。你可以像你一样使用IList&lt;T&gt; 属性。您只需要指定字段的起始索引即可。

    Map( m => m.Attributes ).Index( 2 );
    

    【讨论】:

    • 我在你的其他帖子中也看到了这个版本 3。我需要这个功能,但我没有找到这个版本...... Nuget 现在只提供最高版本 2.16.3。我怎样才能得到它?
    • 在 NuGet 管理器中,选中该框以启用预发布版本。如果你是通过控制台做的,你可以做Install-Package CsvHelper -Pre
    • 谢谢你,我做到了,但现在我可以使用一些关于如何映射 IEnumerable 属性的帮助或文档。在我的情况下,我尝试将可枚举的多个值连接到一个值用于出口。
    • 3.0 的文档还没有完成。暂时查看单元测试以获取示例。
    • @JoshClose 由于我不知道起始索引,有没有办法像 StartsWith('Attribute') 一样映射这个属性。
    【解决方案3】:

    我不知道这个库,所以以下可能会有所帮助。

    如果您已经有一个 IEnumerable&lt;IEnumerable&lt;string&gt;&gt; 代表所有列的所有记录,您可以使用此 Linq 查询来获取您的 List&lt;Person&gt;IList&lt;string&gt; Attributes

    IEnumerable<IEnumerable<string>> allRecords = .....;
    IEnumerable<Person> allPersons = allRecords
    .Select(rec => 
    {
        var person = new Person();
        person.FirstName = rec.ElementAt(0);
        person.LastName = rec.ElementAtOrDefault(1);
        person.Attributes = rec.Skip(2).ToList();
        return person;
    }).ToList();
    

    编辑:下载库,至少经过编译,无法真正测试:

    IList<Person> allPersons = new List<Person>();
    using (var reader = new CsvHelper.CsvReader(yourTextReader))
    {
        while (reader.Read())
        {
            var person = new Person();
            person.FirstName = reader.CurrentRecord.ElementAt(0);
            person.LastName = reader.CurrentRecord.ElementAtOrDefault(1);
            person.Attributes = reader.CurrentRecord.Skip(2).ToList();
            allPersons.Add(person);
        }
    }
    

    【讨论】:

    • 我喜欢在这里使用 linq,我最终在库的范围内做了类似的事情
    • @Neil:我已经下载了库并编辑了我的答案,以提供一些可以编译的东西,并且可能会给你一个想法。但是,我无法对其进行测试,现在必须上床睡觉;)
    【解决方案4】:

    您实际上不需要预先定义列名,您可以从FieldHeaders 属性中获取它们。因此,在 Neil 答案的更动态版本中,您可以这样定义您的 Mapper

    public sealed class PersonMap : CsvClassMap<Person> {
        public override void CreateMap() {
            Map(m => m.FirstName).Name("FirstName").Index(0);
            Map(m => m.LastName).Name("LastName").Index(1);
            Map(m => m.Attributes).ConvertUsing(row =>
                (row as CsvReader)?.FieldHeaders
                     .Where(header => header.StartsWith("Attribute"))
                     .Select(header => row.GetField<string>(header))
                     .Where(value => !string.IsNullOrWhiteSpace(value))
                     .ToList()
            );
        }
    }
    

    【讨论】:

    • 它不起作用。我收到编译错误,无法通过引用转换、装箱转换、拆箱转换、包装转换或空类型转换将类型“Person”转换为“CsvHelper.CsvReader”
    • 对我不起作用,我知道FieldHeadersCsvReader 属性上不存在
    • @Sigex,您使用的是哪个版本的 CSVHelper?我前段时间写了这个答案,可能某些属性已经改变了
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多