C# Datatable 按两个字段分组,将 4 个字段放入数组中

标签 c# arrays linq types grouping

我有一个 XLSX 文件,有 4 列(id、表单名称、数据、图像路径)。我的最终目标是根据 id 和表单名称将所有这些行分组为简洁的分组,每个表单包含一组文档。

|ID        | Form     | Date     | ImagePath    |
| -------- | -------- | -------- | ------------ |
|123       | ABC      | 8/1/2023 | c:/pic1.jpg  |
|123       | DEF      | 8/2/2023 | c:/file1.jpg |
|123       | DEF      | 8/2/2023 | c:/file2.jpg |
|123       | DEF      | 8/2/2023 | c:/file3.jpg |
|456       | GHI      | 8/1/2023 | c:/test1.jpg |
|456       | GHI      | 8/1/2023 | c:/test2.jpg |

我想做的是:

|ID        | Form     | Date     | ImagePath    |
| -------- | -------- | -------- | ------------ |
|123       | ABC      | 8/1/2023 | c:/pic1.jpg  |
|123       | DEF      | 8/2/2023 | c:/file1.jpg |
|          |          |          | c:/file2.jpg |
|          |          |          | c:/file3.jpg |
|456       | GHI      | 8/1/2023 | c:/test1.jpg |
|456       |          |          | c:/test2.jpg |

一旦我将其转换为该格式,我就可以迭代它们并对每个 ID 和表单进行一些处理。

我创建了一个类:

public string ID {get; set;}
public string Form {get; set;}
public DateTime docDate {get; set;}
public List<string> files {get; set;)

在我的程序中我尝试过:

Foreach (DataRow row in caseDT.Rows)
{
   for(int i = 0; i < caseDT.Columns.Count; i++)
   {
      // tried multiple if's
   }
}

我想这可以通过 linq 语句来完成,但还没有成功。

var data = caseDT.AsEnumerable();
CaseDoc[] results = data
   .GroupBy(x => new {ID = x.Field<string>("ID"), Form = x.Field<string>("Form")})
   .Select(x => new CaseDoc
    {
       ID = x.key.ID,
       Form = x.key.CaseDoc,
       docDate = // how do I get docdate
       files = // do I do another select here for all the items from image path??
    }

虽然我的测试样本很小,但最终 XLS 的总体大小将为 9000 行。

任何方向将不胜感激。

最佳答案

首先,我建议您创建一个类来表示 XLSX 文件中的一行。根据您共享的数据,类似这样的内容将接近所需的内容:

 public class Document
 {
     public string Id {get; set;}
     public string Form {get; set;}
     public DateTime DocumentDate {get; set;}
     public string ImagePath {get; set;)
 }

读取 XLSX 文件并为每一行创建 Document 类的实例后,您可以继续进行如下分组。我假设您已将所有解析的行分配到名为 documents 的变量中。

关于要创建的组,您可以定义一个类并将每个组结果投影到此类的实例中,也可以使用匿名类。假设您想要使用第一个选项(这是我从您最初的帖子中了解到的),定义一个类。

public class DocumentsGroup
{
    public string Id { get; set; }
    public string Form { get; set; }

    // Every attribute of the group that is not in the key you use 
    // to create the group could be defined as a List<T>, where
    // T is the corresponding type  

    public List<DateTime> DocumentsDates { get; set; }
    public List<string> ImagesPaths { get; set; }
}

var result = documents.GroupBy(document => new 
                      {
                          Id = document.Id, 
                          Form = document.Form 
                      })
                      .Select(gr => new DocumentsGroup 
                      {
                          Id = gr.Id,
                          Form = gr.Form,
                          DocumentsDates = gr.Select(item => item.DocumentDate)
                                             .ToList()
                          ImagesPaths = gr.Select(item => item.ImagePath)
                                          .ToList()
                      })
                      .ToList();

注意:如果您还希望 DocumentDate 成为分组的一部分 - 我不确定 100%,无论您是否想要这个 -,那么 a) 您只需更改 DocumentsGroup -请检查那里的注释 -,&b) 在用于分组的键中也包含此属性。

关于C# Datatable 按两个字段分组,将 4 个字段放入数组中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76980116/

相关文章:

c# - Linq - 在 Lambda 表达式中使用数组来获取多条记录

c# - Linq 包含对象的方法

c# - 创建具有过期时间的公共(public)临时文件

c# - 无法使用 {} 将事件添加到动态生成的控件

c# - 如何判断ParameterInfo是否为泛型?

javascript - 交叉监听多个事件并触发回调

c# - 在这种情况下,为什么在 lambda 中调用方法时将方法组传递给重载方法会导致歧义?

c++ - (C++) 我的函数不返回数组

php - array_push 在函数中不起作用,PHP

c# - Linq 选择两个列表中都存在的项目