我正在使用 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; }
}
我希望一步完成此操作,我确信我可以有一个中间步骤,将其放入具有匹配属性的对象中,但最好一次性完成此操作
这可以作为映射器发挥作用。
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>();
}
}
版本 3 支持读取和写入
IEnumerable
属性。您可以像您一样使用 IList<T>
属性。您只需要指定字段的起始索引即可。
Map( m => m.Attributes ).Index( 2 );
我不知道这个库,所以以下内容可能有帮助,也可能没有帮助。
如果您已经有一个代表所有列的所有记录的
IEnumerable<IEnumerable<string>>
,您可以使用此 Linq 查询来获取带有 List<Person>
的 IList<string> 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);
}
}
您实际上不需要事先定义列名称,您可以从
FieldHeaders
属性获取它们。因此,在尼尔的答案的更动态版本中,您可以这样定义 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()
);
}
}
在最新版本中,您可以在创建
Convert
时访问
ClassMap
我认为对于你的需求,它看起来像这样:
class PersonMap : ClassMap<Person>
{
public PersonMap()
{
Map(m => m.FirstName).Name("FirstName");
Map(m => m.LastName).Name("LastName");
Map(result => result.Attributes).Convert(args => args.Row.HeaderRecord
.Where(column => column.StartsWith("Attribute"))
.Select(column => args.Row.GetField(column))
.ToList());
}
}
使用它已经有一段时间了,pure
ClassMap
绝对比大多数hacks更强大。
您需要使用 CsvHelper 上下文注册类映射。