【问题标题】:Mapping data to a list when I have the position index当我有位置索引时将数据映射到列表
【发布时间】:2020-02-07 14:33:34
【问题描述】:

(我正在使用 CSVHelper 包)

你好,

我有一个 sbyte[] 数组,它保存 CSV 文件中每个标题列的位置。数组定义如下,

public sbyte[] ColumnIndex = new sbyte[Enum.GetNames(typeof(MyEnum)).Length];

并说我有一个如下所示的 CSV 文件:

col1,col2,col3,col4
name1,empId1,241682-27638-USD-CIGGNT ,1
name2,empId2,241682-27638-USD-OCGGINT ,1
name3,empId3,241942-37190-USD-GGDIV ,2
name4,empId4,241942-37190-USD-CHYOF ,1
name5,empId5,241942-37190-USD-EQPL ,1
name6,empId6,241942-37190-USD-INT ,1
name7,empId7,242066-15343-USD-CYJOF ,3
name8,empId8,242066-15343-USD-CYJOF ,3
name9,empId9,242066-15343-USD-CYJOF ,3
name10,empId10,241942-37190-USD-GGDIV ,2

现在调用字节数组并传递Enum 索引将返回标题行中的位置:

int conversion = (int)MyEnum.col3;

ColumnIndex[conversion]);

returns 2

现在这一切正常,但我似乎很难弄清楚如何根据我拥有的位置索引将每列与其信息映射到分隔 List<string>

我尝试使用以下代码将所有字段放在一个 List<string> 中:

 public List<string> ParseEntire(aliasType type, string PathToFile) {

            List<string> result = new List<string>();
            using (TextReader fileReader = File.OpenText(PathToFile)) {
                var csv = new CsvReader(fileReader, CultureInfo.InvariantCulture);

                string value;
                while (csv.Read()) {
                    for (int i = 0; csv.TryGetField<string>(i, out value); i++) {

                        result.Add(value);
                    }
                }
            }
            return result;
        }

但是,这没有用,因为我无法知道每个标题的位置。我觉得使用CSVHelper 包有一种更简单的方法,我只是让一个简单的任务复杂化。任何帮助将不胜感激。

编辑: 对于下面的Emun

  public enum aliasType {
            col5,
            col4,
            col3,
            col2,
            col1
        }

执行代码将位置索引映射到ColumnIndex 后,它看起来像这样:

ColumnIndex  {sbyte[4]}
[0]             [-1]
[1]             [3] 
[2]             [2]
[3]             [1]
[4]             [0]

我这样做主要是因为我不知道标题行包含什么。因此,我尽可能多地提取信息,当我返回 -1 的索引时,我知道该特定字段不存在。

更新:

以下代码使用Intersect 与我尝试提取的同一标题列的不同别名进行比较。

 public List<string> HeaderColumnParser(aliasType type, string PathToFile) {

            List<string> result = new List<string>();
            using (TextReader fileReader = File.OpenText(PathToFile)) {
                var csv = new CsvReader(fileReader, CultureInfo.InvariantCulture);
                CSVBOM extract = new CSVBOM("", CSVBOM.BOMFileType.csv);

                csv.Read();
                csv.ReadHeader();
                string[] header = csv.Context.HeaderRecord;
                IEnumerable<string> CommonHeaders;

                foreach (aliasType foo in Enum.GetValues(typeof(aliasType))) {
                    int res = Convert.ToInt32(foo);

                    switch (res) {
                        case 0:
                            // get matching string
                            CommonHeaders = header.Intersect(ReferenceDesignatorAliases);
                            ColumnIndex[res] = extract.ExtractIndexHeader(CommonHeaders, header);
                            break;
                        case 1:
                            CommonHeaders = header.Intersect(ManufacturersPartNumberAliases);
                            ColumnIndex[res] = extract.ExtractIndexHeader(CommonHeaders, header);
                            break;
                        case 2:
                            CommonHeaders = header.Intersect(ValueAliases);
                            ColumnIndex[res] = extract.ExtractIndexHeader(CommonHeaders, header);
                            break;
                        case 3:
                            CommonHeaders = header.Intersect(DescriptionShortAliases);
                            ColumnIndex[res] = extract.ExtractIndexHeader(CommonHeaders, header);
                            break;
                        case 4:
                            CommonHeaders = header.Intersect(DescriptionLongAliases);
                            ColumnIndex[res] = extract.ExtractIndexHeader(CommonHeaders, header);
                            break;
                        case 5:
                            CommonHeaders = header.Intersect(ManufacturerAliases);
                            ColumnIndex[res] = extract.ExtractIndexHeader(CommonHeaders, header);
                            break;
                        case 6:
                            CommonHeaders = header.Intersect(DNIAliases);
                            ColumnIndex[res] = extract.ExtractIndexHeader(CommonHeaders, header);
                            break;
                        case 7:
                            CommonHeaders = header.Intersect(DataSheetAliases);
                            ColumnIndex[res] = extract.ExtractIndexHeader(CommonHeaders, header);
                            break;
                        default:
                            throw new Exception("Alias type is not recognized");
                    }
                }

            }
            return result;
        }

我的枚举和别名字符串数组:

   public enum aliasType {
            ReferenceDesignatorAliases,
            ManufacturersPartNumberAliases,
            ValueAliases,
            DescriptionShortAliases,
            DescriptionLongAliases,
            ManufacturerAliases,
            DNIAliases,
            DataSheetAliases
        }

        //Returns -1 meaning not found
        public sbyte[] ColumnIndex = new sbyte[Enum.GetNames(typeof(aliasType)).Length];

        public string[] ReferenceDesignatorAliases = { "Reference Designator", "RefDes", "Designator", "Annotation" };
        public string[] ManufacturersPartNumberAliases = { "Manufacturer's Part Number", "MPN", "PN", "part Number" };
        public string[] ValueAliases = { "Value" };
        public string[] DescriptionShortAliases = { "Description Short", "Description" };
        public string[] DescriptionLongAliases = { "Description Long" };
        public string[] ManufacturerAliases = { "Manufacturer", "MF" };
        public string[] DNIAliases = { "DNI", "Do Not Install" };
        public string[] DataSheetAliases = { "DataSheet", "Data Sheet" };

【问题讨论】:

  • 我不确定我是否理解。 ColumnIndex 的列顺序是否与 CSV 文件不同?
  • 我的方法是,在我传入标题列的 Enum 值后,我想要该位置并返回该位置。我将编辑我的答案以进一步解释这一点

标签: c# csv dictionary csvhelper


【解决方案1】:

我相信我对您要完成的工作有了更好的了解。如果这能解决您的问题,请告诉我。

public static void Main(string[] args)
{
    using (MemoryStream stream = new MemoryStream())
    using (StreamWriter writer = new StreamWriter(stream))
    using (StreamReader reader = new StreamReader(stream))
    using (CsvReader csv = new CsvReader(reader, CultureInfo.InvariantCulture))
    {
        writer.WriteLine("MF,RefDes,MPN,Value");
        writer.WriteLine("name1,empId1,241682-27638-USD-CIGGNT ,1");
        writer.WriteLine("name2,empId2,241682-27638-USD-OCGGINT ,1");
        writer.WriteLine("name3,empId3,241942-37190-USD-GGDIV ,2");
        writer.WriteLine("name4,empId4,241942-37190-USD-CHYOF ,1");
        writer.Flush();
        stream.Position = 0;

        string[] ReferenceDesignatorAliases = { "Reference Designator", "RefDes", "Designator", "Annotation" };        

        csv.Read();
        csv.ReadHeader();

        var result = new List<string>();

        if (csv.Context.HeaderRecord.Intersect(ReferenceDesignatorAliases).Count() > 0)
        {
            while (csv.Read())
            {
                if (csv.TryGetField(csv.GetFieldIndex(ReferenceDesignatorAliases), out string value))
                {
                    result.Add(value);
                }
            }
        }
    }

    Console.ReadKey();
}

这是另一个选项,它可以一次获取所有列,然后您可以将它们拆分为单独的列列表。

public class Program
{
    public static void Main(string[] args)
    {
        List<Foo> records;

        using (MemoryStream stream = new MemoryStream())
        using (StreamWriter writer = new StreamWriter(stream))
        using (StreamReader reader = new StreamReader(stream))
        using (CsvReader csv = new CsvReader(reader, CultureInfo.InvariantCulture))
        {
            writer.WriteLine("MF,RefDes,MPN,Value");
            writer.WriteLine("name1,empId1,241682-27638-USD-CIGGNT ,1");
            writer.WriteLine("name2,empId2,241682-27638-USD-OCGGINT ,1");
            writer.WriteLine("name3,empId3,241942-37190-USD-GGDIV ,2");
            writer.WriteLine("name4,empId4,241942-37190-USD-CHYOF ,1");
            writer.Flush();
            stream.Position = 0;

            csv.Configuration.RegisterClassMap<FooClassMap>();

            records = csv.GetRecords<Foo>().ToList();                
        }

        if (!records.All(r => r.ReferenceDesignator == null))
        {
            var ReferenceResult = records.Select(r => r.ReferenceDesignator).ToList();
        }

        if (!records.All(r => r.Manufacturer == null))
        {
            var ManufacturerResult = records.Select(r => r.Manufacturer).ToList();
        }

        Console.ReadKey();
    }
}

public class Foo
{
    public string ReferenceDesignator { get; set; }
    public string ManufacturersPartNumber { get; set; }
    public int? Value { get; set; }
    public string DescriptionShort { get; set; }
    public string DescriptionLong { get; set; }
    public string Manufacturer { get; set; }
    public string Dni { get; set; }
    public string DataSheet { get; set; }
}

public class FooClassMap : ClassMap<Foo>
{
    public FooClassMap()
    {
        Map(m => m.ReferenceDesignator).Optional().Name("Reference Designator", "RefDes", "Designator", "Annotation");
        Map(m => m.ManufacturersPartNumber).Optional().Name("Manufacturer's Part Number", "MPN", "PN", "part Number");
        Map(m => m.Value).Optional();
        Map(m => m.DescriptionShort).Optional().Name("Description Short", "Description");
        Map(m => m.DescriptionLong).Optional().Name("Description Long");
        Map(m => m.Manufacturer).Optional().Name("Manufacturer", "MF");
        Map(m => m.Dni).Optional().Name("DNI", "Do Not Install");
        Map(m => m.DataSheet).Optional().Name("DataSheet", "Data Sheet");
    }
}

【讨论】:

  • 感谢您的回答。这似乎根据标题名称在枚举中的位置来获取索引。我的问题是我不知道标题字段是如何组织的,有些甚至可能丢失。无论安排如何,我都会用我用来查找位置的代码更新我的问题。
  • 我更新了我的答案。它应该处理不存在的列,以及列的不同名称。
  • 这对我有用,但我想知道,因为我必须为多个别名数组执行此操作,我可以指向文件的开头,因为 csv.Read() 在我尝试返回 false 时使用第二组别名数组读取。
  • 您可以设置stream.Position = 0,但我会尝试将它们全部放在while (csv.Read()) 中,而不是再次循环回文件。
猜你喜欢
  • 2020-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-20
  • 1970-01-01
相关资源
最近更新 更多