首页 > 解决方案 > JavaScript - 递归构建树形数据结构

问题描述

我有一个名为 tree 的函数,它接受对象数组(作为数据库中的数据字段)和字符串数组作为键。该函数循环遍历 rowsArray 并基于 keyArray 递归地创建具有嵌套属性的对象。

const tree = (rowsArray, keysArray) => {
  return rows.reduce((acc, row) => {
    const groupBy = (row, keys,) => {
      const [first, ...rest] = keys;

      if (!first) return [row];

      return {
        [row[first]]: groupBy(row, rest),
      }
    };
    acc = {...groupBy(row, keys), ...acc};
    return acc;
  }, {});
}

数据如下:

const data = [{
        ID: 1,
        Main: "Financial",
        Sub: "Forecasts",
        Detail: "General"
    }, {
        ID: 2,
        Main: "Financial",
        Sub: "HR",
        Detail: "Headcount"
}];

const result1 = tree(data, ["Main", "Sub", "Detail"]);
console.log(result1); 

当我记录结果时,我得到:

/*
// actual output
  { 
    Financial: { 
      Forecasts:  { 
        General: [Array] 
      } 
    } 
  }

鉴于,我想得到以下信息:

  // expected
  { 
    Financial: { 
      Forecasts:  { 
        General: [Array] 
      },
      HR:  { 
        Headcount: [Array] 
      }
    } 
  }
  */

问题是,主函数中的 acc 变量被覆盖,我得到了新对象,而不是累积的,我不太确定如何递归地构建这个对象。我试图将 acc 的实例传递给 groupBy 函数(以记住以前的结果),但没有运气。

您知道如何重写树函数或 groupBy 函数来实现我的目标吗?谢谢!

标签: javascriptarraysobjectrecursiontree

解决方案


你可以这样做:

function tree(rows, keys) {
    return rows.reduce( (acc, row) => {
        keys.reduce( (parent, key, i) =>
            parent[row[key]] = parent[row[key]] || (i === keys.length - 1 ? [row] : {})
        , acc);
        return acc;
    }, {});
}

const data = [{ID: 1,Main: "Financial",Sub: "Forecasts",Detail: "General"}, {ID: 2,Main: "Financial",Sub: "HR", Detail: "Headcount" }];
const result1 = tree(data, ["Main", "Sub", "Detail"]);
console.log(result1); 

请注意,扩展语法会产生浅拷贝。相反,在这个解决方案中,累加器被传递给内部reduce。所以我们实际上将新行的分层数据合并到现场的累加器中。


推荐阅读