【问题标题】:CsvHelper type conversion, column with string and ints to intCsvHelper 类型转换,带字符串和整数的列到整数
【发布时间】:2021-11-03 03:50:07
【问题描述】:

我有一个人为的 csv 文件

  "Id","Name"
  "10","Foo"
  "Team1Id","Joe"
  "Team1Id","Blogs"
  "Team2Id","Foo Bar"

public class MyClass
{
    public int Id { get; set; }
    public string Name { get; set; }
}
public class MyClassMap : CsvHelper.Configuration.ClassMap<MyClass>
{
    public MyClassMap()
    {
        Map(m => m.Id).Name("Id").???Convert???
        Map(m => m.Name).Name("Name");
    }
}

我想将 Id 列映射到一个 int,所以我想我想自定义转换“Team1Id”和“Team2Id”到一些相关的固定值(“Team1Id”=> -1,“Team2Id”=> - 2)

【问题讨论】:

  • 根据文档,您可以滚动自己的 TypeConverter ,例如:joshclose.github.io/CsvHelper/examples/configuration/class-maps/…
  • 您是否要剥离非 nUmbers 并使结果为负数的关系,因此 Team278Id 将是 -278?
  • @CaiusJard 我在想,如果字典中有 100,000 个键,您必须全部阅读它们才能确定下一个值。但是有办法解决这个问题,所以我删除了评论。
  • @stuartd 啊,有道理.. 是的,我想我会保持配对号码nextId,如果我正在制作一个新的字典条目,我会d[somelkey] = nextId--;,所以我不必 Min() 字典值
  • 谢谢@david,辛苦了。 lidqy TypeConverter 示例覆盖了 ConvertFromString / ConvertToString,我看不出这有什么帮助。 stuart / caius 我在列中只有几个文本项,它们实际上并不包含数字,而是巧妙的解决方案。谢谢大家

标签: c# csvhelper


【解决方案1】:

这是否符合您的要求?

void Main()
{
    var mappings = new Dictionary<string, int> { { "Team1Id", -1 }, {"Team2Id", -2 }};
    
    using (var reader = new StringReader("Id,Name\n10,Foo\nTeam1Id,Joe\nTeam1Id,Blogs\nTeam2Id,Foo Bar"))
    using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
    {
        csv.Context.RegisterClassMap(new MyClassMap(mappings));
        var records = csv.GetRecords<MyClass>().ToList();
    }   
}

public class MyClassMap : ClassMap<MyClass>
{
    public MyClassMap(IDictionary<string,int> mappings)
    {
        Map(x => x.Id).Convert(args =>
        {
            var idValue = args.Row.GetField("Id");
            
            if (mappings.ContainsKey(idValue))
            {
                return mappings[idValue];
            } else
            {
                int.TryParse(idValue, out int value);
                
                return value;
            }
            
        });
        Map(x => x.Name);
    }
}

public class MyClass
{
    public int Id { get; set; }
    public string Name { get; set; }
}

【讨论】:

    【解决方案2】:

    这是对 D.Specht 答案的修改,以纳入 stuartd 的评论

    void Main()
    {
        using var reader = new StringReader("Id,Name\n10,Foo\nTeam1Id,Joe\nTeam1Id,Blogs\nTeam2Id,Foo Bar");
        using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
        csv.Context.RegisterClassMap(new MyClassMap(mappings));
        var records = csv.GetRecords<MyClass>().ToList();
    }
    
    public class MyClassMap : ClassMap<MyClass>
    {
        private _mappings = new Dictionary<string, int>();
        private _nextId = -1;
    
        public MyClassMap(IDictionary<string,int> mappings)
        {
            Map(x => x.Id).Convert(args =>
            {
                var idValue = args.Row.GetField("Id");
                
                if(int.TryParse(idValue, out int value))
                    return value;
               
                if (_mappings.TryGetValue(idValue, out int value))
                    return value;
                else
                    return (mappings[idValue] = nextId--);
                
            });
            Map(x => x.Name);
        }
    }
    
    public class MyClass
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    

    如果你只是想去掉文本只留下数字,那么 team1234xyz 变成 -1234 和 123abc456 变成 -123456:

    void Main()
    {
        using var reader = new StringReader("Id,Name\n10,Foo\nTeam1Id,Joe\nTeam1Id,Blogs\nTeam2Id,Foo Bar");
        using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
        csv.Context.RegisterClassMap(new MyClassMap(mappings));
        var records = csv.GetRecords<MyClass>().ToList();
    }
    
    public class MyClassMap : ClassMap<MyClass>
    {
        public MyClassMap(IDictionary<string,int> mappings)
        {
            Map(x => x.Id).Convert(args =>
            {
                var idValue = args.Row.GetField("Id");
                
                if(int.TryParse(idValue, out int value))
                    return value;
                else
                    return -Convert.ToInt32(new string(value.Where(c => Char.IsDigit(c))));
                
            });
            Map(x => x.Name);
        }
    }
    
    public class MyClass
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多