我正在使用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; }
}
我希望一步完成这一步,我确信我可以有一个中间步骤,我放入一个具有匹配属性属性的对象但是在一个
答案 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);