You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在C#中将扁平数据集转换为嵌套层级结构的高效实现方法

实现扁平数据到嵌套模型的高效转换

这个需求太常见了——把从关联多外键的数据库视图中查询到的扁平数据,聚合分组转换成嵌套的对象模型。最简便高效的方式是通过一次遍历完成分组聚合,时间复杂度为O(n),只需要遍历一次原数据即可,完全不需要额外的嵌套循环。

先明确输入和期望输出

输入扁平数据(整理为结构化对象数组)

const flatData = [
  { Id: 1, Name: 'N1', TagId: 'T1', DepartmentId: null, Code: null },
  { Id: 1, Name: 'N1', TagId: 'T2', DepartmentId: null, Code: null },
  { Id: 1, Name: 'N1', TagId: null, DepartmentId: 'D1', Code: null },
  { Id: 1, Name: 'N1', TagId: null, DepartmentId: null, Code: 'C1' },
  { Id: 1, Name: 'N1', TagId: null, DepartmentId: null, Code: 'C2' },
  { Id: 2, Name: 'N2', TagId: 'T3', DepartmentId: null, Code: null },
  { Id: 2, Name: 'N2', TagId: null, DepartmentId: 'D2', Code: null }
];

期望输出的嵌套模型

[
  { Id: 1, Name: 'N1', TagIds: ['T1', 'T2'], DepartmentId: 'D1', Codes: ['C1', 'C2'] },
  { Id: 2, Name: 'N2', TagIds: ['T3'], DepartmentId: 'D2', Codes: [] }
]

具体实现方案

前端JavaScript版本(用reduce方法)

reduce是数组原生方法,专门用来做累加/聚合操作,非常适合这个场景:

const aggregatedData = Object.values(flatData.reduce((acc, item) => {
  // 用Id作为唯一分组键
  const groupKey = item.Id;
  
  // 如果当前分组不存在,初始化嵌套结构
  if (!acc[groupKey]) {
    acc[groupKey] = {
      Id: item.Id,
      Name: item.Name,
      TagIds: [],
      DepartmentId: null,
      Codes: []
    };
  }

  // 非空TagId加入数组
  if (item.TagId) acc[groupKey].TagIds.push(item.TagId);
  // 非空DepartmentId直接赋值(假设每个Id对应唯一部门)
  if (item.DepartmentId) acc[groupKey].DepartmentId = item.DepartmentId;
  // 非空Code加入数组
  if (item.Code) acc[groupKey].Codes.push(item.Code);

  return acc;
}, {}));

后端Python版本(用字典分组)

如果是在后端处理,用字典作为分组容器的思路完全一致:

flat_data = [
    {"Id": 1, "Name": "N1", "TagId": "T1", "DepartmentId": None, "Code": None},
    {"Id": 1, "Name": "N1", "TagId": "T2", "DepartmentId": None, "Code": None},
    {"Id": 1, "Name": "N1", "TagId": None, "DepartmentId": "D1", "Code": None},
    {"Id": 1, "Name": "N1", "TagId": None, "DepartmentId": None, "Code": "C1"},
    {"Id": 1, "Name": "N1", "TagId": None, "DepartmentId": None, "Code": "C2"},
    {"Id": 2, "Name": "N2", "TagId": "T3", "DepartmentId": None, "Code": None},
    {"Id": 2, "Name": "N2", "TagId": None, "DepartmentId": "D2", "Code": None}
]

aggregated_map = {}
for item in flat_data:
    key = item["Id"]
    if key not in aggregated_map:
        aggregated_map[key] = {
            "Id": item["Id"],
            "Name": item["Name"],
            "TagIds": [],
            "DepartmentId": None,
            "Codes": []
        }
    # 处理各字段
    if item["TagId"] is not None:
        aggregated_map[key]["TagIds"].append(item["TagId"])
    if item["DepartmentId"] is not None:
        aggregated_map[key]["DepartmentId"] = item["DepartmentId"]
    if item["Code"] is not None:
        aggregated_map[key]["Codes"].append(item["Code"])

# 把字典值转成列表就是最终结果
aggregated_data = list(aggregated_map.values())

额外思路:数据库层面聚合

如果你的扁平数据是直接从数据库视图查询出来的,也可以考虑在数据库层面完成聚合:

  • 对于MySQL,可以用GROUP_CONCAT函数把TagId和Code拼接成逗号分隔的字符串,查询后在应用层转成数组;
  • 对于PostgreSQL/SQL Server,可以用STRING_AGG函数做类似操作。

不过如果已经拿到了扁平数据,应用层的一次遍历聚合是最直接高效的选择。

内容的提问来源于stack exchange,提问作者Shyamal Parikh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:20:39