CsvHelper - 将多列读入单个列表

时间:2013-06-27 21:23:20

标签: c# csvhelper

我正在使用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; }
}

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

4 个答案:

答案 0 :(得分:20)

这可以作为映射器。

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>();
    }
}

答案 1 :(得分:2)

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

如果您已经有IEnumerable<IEnumerable<string>>表示包含所有列的所有记录,则可以使用此Linq查询来获取List<Person> IList<string> Attributes的<{1}}:

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);
    }
}

答案 2 :(得分:1)

您实际上不需要事先定义列名,您可以从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()
        );
    }
}

答案 3 :(得分:1)

版本3支持读写IEnumerable属性。您可以像使用IList<T>属性一样使用Map( m => m.Attributes ).Index( 2 ); 属性。您只需指定字段的起始索引。

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'
import { recentData } from '../actions/index'
import { allTimeData } from '../actions/index'

export default class TableBoard extends Component {
  constructor(props){
    super(props);
  }
  componentDidMount() {
    //Is there better way to initialize the background-color???
    $("#col-recent").css("background-color", "lightblue");
    this.props.recentData() //fetch data most recent top
  }
  renderData(userData,index){
    const FCC_URL = 'https://www.freecodecamp.com/'
    const img = userData.img
    const name = userData.username;
    const recent = userData.recent;
    const allTime = userData.alltime;
    return(
      <tr key={name}>
        <td className="rank">{index + 1}</td>
        <td>
          <img className="img-responsive"
          src={img}
          alt='FCC profile'
          /> <a href={FCC_URL + name}>{name}</a>
        </td>
        <td className="recent">{recent}</td>
        <td className="all-time">{allTime}</td>
      </tr>
    )
  }
  getRecentData(){
    $("#col-recent").css("background-color", "lightblue");
    $("#col-alltime").css("background-color", "#e2e2e2");
    this.props.recentData()
  }
  getAllTimeData(){
    $("#col-alltime").css("background-color", "lightblue");
    $("#col-recent").css("background-color", "#e2e2e2");
    this.props.allTimeData();
  }
  render(){
    return(
      <table className="table table-hover table-striped table-bordered">
        <thead>
          <tr>
            <th className="rank">#</th>
            <th className="username">Camper Name</th>
            <th id='col-recent'className="recent clickable"
              onClick={this.getRecentData.bind(this)}
              >Points in 30 days
            </th>
            <th id='col-alltime' className="all-time clickable"
              onClick={this.getAllTimeData.bind(this)}
              >All-time Posts
            </th>
          </tr>
        </thead>
        <tbody>
          {this.props.FCCData.map(this.renderData)}
        </tbody>
      </table>
    )
  }
}
function mapStateToProps(state){
  return {
    FCCData: state.collectData
  }
}
function mapDispatchToProps(dispatch){
  return bindActionCreators({ recentData, allTimeData }, dispatch)
}

export default connect(mapStateToProps, mapDispatchToProps)(TableBoard);