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

如何在JavaScript中基于动态分组创建层级数据并实现值的向上汇总,同时解决大数据量下浏览器卡顿问题

动态分组构建层级汇总数据结构的问题

我需要实现一个功能:根据动态指定的分组字段创建层级化的数据结构,同时将数值字段向上汇总到顶层节点。但目前处理大量数据时会出现浏览器卡顿的情况,而且我自己写的函数没法正常工作。下面是相关的细节:

示例输入数据

var data = [ 
  { "country":"Spain", "orderNumber":10394, "year":2018, "countrycode":"es", "quantityOrdered":30, "priceEach":60.28, "productName":"1950's Chicago Surface Lines Streetcar", "productLine":"Trains", "sortkey":3, "productCode":"S32_3207", "month":"March", "extendedPrice":1808.4, "orderDate":"2018-03-15 00:00:00" }, 
  { "country":"France", "orderNumber":10395, "year":2018, "countrycode":"fr", "quantityOrdered":32, "priceEach":105.33, "productName":"1972 Alfa Romeo GTA", "productLine":"Classic Cars", "sortkey":3, "productCode":"S10_4757", "month":"March", "extendedPrice":3370.56, "orderDate":"2018-03-17 00:00:00" }, 
  { "country":"France", "orderNumber":10395, "year":2018, "countrycode":"fr", "quantityOrdered":33, "priceEach":69.12, "productName":"2001 Ferrari Enzo", "productLine":"Classic Cars", "sortkey":3, "productCode":"S12_1108", "month":"March", "extendedPrice":2280.96, "orderDate":"2018-03-17 00:00:00" }, 
  { "country":"France", "orderNumber":10395, "year":2018, "countrycode":"fr", "quantityOrdered":46, "priceEach":123.76, "productName":"Diamond T620 Semi-Skirted Tanker", "productLine":"Trucks and Buses", "sortkey":3, "productCode":"S50_1392", "month":"March", "extendedPrice":5692.96, "orderDate":"2018-03-17 00:00:00" }, 
  { "country":"France", "orderNumber":10395, "year":2018, "countrycode":"fr", "quantityOrdered":45, "priceEach":199.49, "productName":"1962 City of Detroit Streetcar", "productLine":"Trains", "sortkey":3, "productCode":"S50_1514", "month":"March", "extendedPrice":8977.05, "orderDate":"2018-03-17 00:00:00" }, 
  { "country":"USA", "orderNumber":10396, "year":2018, "countrycode":"us", "quantityOrdered":33, "priceEach":185.13, "productName":"1969 Ford Falcon", "productLine":"Classic Cars", "sortkey":3, "productCode":"S12_3891", "month":"March", "extendedPrice":6109.29, "orderDate":"2018-03-23 00:00:00" }, 
  { "country":"USA", "orderNumber":10396, "year":2018, "countrycode":"us", "quantityOrdered":33, "priceEach":159.81, "productName":"1903 Ford Model A", "productLine":"Vintage Cars", "sortkey":3, "productCode":"S18_3140", "month":"March", "extendedPrice":5273.73, "orderDate":"2018-03-23 00:00:00" }, 
  { "country":"USA", "orderNumber":10396, "year":2018, "countrycode":"us", "quantityOrdered":24, "priceEach":89.75, "productName":"Collectable Wooden Train", "productLine":"Trains", "sortkey":3, "productCode":"S18_3259", "month":"March", "extendedPrice":2154, "orderDate":"2018-03-23 00:00:00" }, 
  { "country":"USA", "orderNumber":10396, "year":2018, "countrycode":"us", "quantityOrdered":45, "priceEach":105.32, "productName":"1904 Buick Runabout", "productLine":"Vintage Cars", "sortkey":3, "productCode":"S18_4522", "month":"March", "extendedPrice":4739.4, "orderDate":"2018-03-23 00:00:00" }, 
  { "country":"USA", "orderNumber":10396, "year":2018, "countrycode":"us", "quantityOrdered":49, "priceEach":116.75, "productName":"18th century schooner", "productLine":"Ships", "sortkey":3, "productCode":"S24_2011", "month":"March", "extendedPrice":5720.75, "orderDate":"2018-03-23 00:00:00" }, 
  { "country":"USA", "orderNumber":10396, "year":2018, "countrycode":"us", "quantityOrdered":27, "priceEach":83.2, "productName":"1912 Ford Model T Delivery Wagon", "productLine":"Vintage Cars", "sortkey":3, "productCode":"S24_3151", "month":"March", "extendedPrice":2246.4, "orderDate":"2018-03-23 00:00:00" }, 
  { "country":"USA", "orderNumber":10396, "year":2018, "countrycode":"us", "quantityOrdered":37, "priceEach":90.57, "productName":"1940 Ford Delivery Sedan", "productLine":"Vintage Cars", "sortkey":3, "productCode":"S24_3816", "month":"March", "extendedPrice":3351.09, "orderDate":"2018-03-23 00:00:00" }, 
  { "country":"USA", "orderNumber":10396, "year":2018, "countrycode":"us", "quantityOrdered":39, "priceEach":66.67, "productName":"The Schooner Bluenose", "productLine":"Ships", "sortkey":3, "productCode":"S700_1138", "month":"March", "extendedPrice":2600.13, "orderDate":"2018-03-23 00:00:00" }, 
  { "country":"France", "orderNumber":10397, "year":2018, "countrycode":"fr", "quantityOrdered":32, "priceEach":80.55, "productName":"The Mayflower", "productLine":"Ships", "sortkey":3, "productCode":"S700_1938", "month":"March", "extendedPrice":2577.6, "orderDate":"2018-03-28 00:00:00" } 
];

我编写的问题代码

我的分组和汇总字段都是动态的,比如:

var groups = ['country', 'productLine', 'month']; // 动态分组字段
var sum = ['priceEach']; // 动态汇总字段

function createGroup (groups, data, sum, childNode) {
 let [primaryGroup, ...rest] = groups;
 let groupedData = data.reduce((acc, current) => {
 let chunk = {
 'Name': current[primaryGroup],
 [primaryGroup]: current[primaryGroup],
 [sum]: data.filter(item => item[primaryGroup] === current[primaryGroup])
 .map(el => el[sum])
 .reduce((total, current) => total + current),
 ...(rest.length > 0 ? {[groups[childNode]]: createGroup(rest, data, sum,childNode+1 )} : {})
 }
 acc.push(chunk)
 return acc
 }, [])
 .reduce((acc, current) => {
 const x = acc.find(item => item[primaryGroup] === current[primaryGroup])
 return !x ? acc.concat([current]) : acc
 }, [])
 return groupedData;
}

const tree = createGroup(groups,data,sum, 1);

这个函数有两个主要问题:一是没法正确生成层级结构和汇总数值,二是处理大量数据时因为重复遍历(比如filter和find)导致浏览器卡顿。

期望的输出格式

我希望得到类似下面的层级结构,数值会向上汇总到顶层节点(示例仅展示部分数据):

[ 
  { 
    "country": [ 
      { 
        "Name":"Spain", 
        "priceEach":60.28, 
        "productLine": [ 
          { 
            "Name":"Trains", 
            "priceEach":60.28, 
            "month": [ 
              { 
                "Name":"March", 
                "priceEach":60.28 
              } 
            ] 
          } 
        ] 
      } 
    ] 
  }, 
  { 
    "country": [ 
      { 
        "Name":"France", 
        "priceEach":578.25, 
        "productLine": [ 
          { 
            "Name":"Classic Cars", 
            "priceEach":174.45, 
            "month": [ 
              { 
                "Name":"March", 
                "priceEach":174.45 
              } 
            ] 
          }, 
          { 
            "Name":"Trucks and Buses", 
            "priceEach":123.76, 
            "month": [ 
              { 
                "Name":"March", 
                "priceEach":123.76 
              } 
            ] 
          }, 
          { 
            "Name":"Trains", 
            "priceEach":199.49, 
            "month": [ 
              { 
                "Name":"March", 
                "priceEach":199.49 
              } 
            ] 
          }, 
          { 
            "Name":"Ships", 
            "priceEach":80.55, 
            "month": [ 
              { 
                "Name":"March", 
                "priceEach":80.55 
              } 
            ] 
          } 
        ] 
      } 
    ] 
  } 
]

解决方案

下面是修复后的函数,解决了层级生成、数值汇总的问题,同时优化了性能,避免大数据量下的卡顿:

var groups = ['country', 'productLine', 'month'];
var sumFields = ['priceEach'];

function createHierarchicalData(groups, data, sumFields) {
  // 递归构建层级的核心函数
  function buildLevel(currentGroups, currentData) {
    if (currentGroups.length === 0) return [];

    const [currentGroup, ...remainingGroups] = currentGroups;
    // 用对象做分组,比数组find高效N倍,适合大数据量
    const groupsMap = {};

    // 遍历一次数据完成分组和初始汇总
    currentData.forEach(item => {
      const key = item[currentGroup];
      if (!groupsMap[key]) {
        // 初始化分组节点
        groupsMap[key] = {
          Name: key,
          [currentGroup]: key
        };
        // 初始化所有汇总字段为0
        sumFields.forEach(field => {
          groupsMap[key][field] = 0;
        });
        // 存储当前分组下的子数据,用于递归
        groupsMap[key]._childData = [];
      }
      // 累加汇总字段数值
      sumFields.forEach(field => {
        groupsMap[key][field] += item[field];
      });
      groupsMap[key]._childData.push(item);
    });

    // 转换为数组,并处理子层级
    return Object.values(groupsMap).map(groupNode => {
      const resultNode = { ...groupNode };
      delete resultNode._childData; // 移除临时存储的子数据

      if (remainingGroups.length > 0) {
        // 递归构建子层级,只传递当前分组下的子数据,减少遍历范围
        resultNode[remainingGroups[0]] = buildLevel(remainingGroups, groupNode._childData);
      }

      return resultNode;
    });
  }

  // 构建顶层结构
  const topLevel = buildLevel(groups, data);
  return groups.length > 0 ? [{ [groups[0]]: topLevel }] : [];
}

// 使用示例
const tree = createHierarchicalData(groups, data, sumFields);
console.log(JSON.stringify(tree, null, 2));

关键优化和修复点:

  • 性能优化:使用对象groupsMap做分组,只遍历一次数据完成分组和汇总,避免了原代码中filter和find带来的多次重复遍历,大幅提升大数据量下的处理速度,解决浏览器卡顿问题。
  • 正确的层级生成:递归时只传递当前分组下的数据子集,确保子层级的汇总和分组是基于父节点的范围,而不是整个数据集。
  • 支持多汇总字段:sumFields可以是数组,支持同时汇总多个数值字段。
  • 正确的汇总逻辑:遍历数据时直接累加当前项的数值,而不是重新筛选数据再求和,逻辑更准确且高效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 18:12:30