首页 > 解决方案 > 使用 lodash 将数组分组为树“子”结构

问题描述

我正在尝试使用下面的 json 对象数组创建一棵树。我想将一个类别设置为另一个类别的子类别,如果它的 sub_category_1 并且我希望 sub_category_2 也成为该 sub_category_1 的子类别

[
  { 
    category: 'CS',
    sub_category_1: null,
    sub_category_2: null
  }, {
    category: 'TS',
    sub_category_1: null,
    sub_category_2: null
  }, {
    category: 'CS',
    sub_category_1: 'Accuracy',
    sub_category_2: null
  }, {
    category: 'CS',
    sub_category_1: 'Accuracy',
    sub_category_2: 'Members Accuracy'
  }
]

我试图链接诸如 groupBy 和 transform 之类的 lodash 方法,但是很难得到我需要的结果格式。

这是我前进方向的骨架:

_(arr).groupBy('category').transform(function(result, obj, type) {
 return result.push({
    name: type,
    children: obj
 });
}).value();

预期输出:

[{
    category: 'CS',
        children: [
            {
                category: 'Accuracy',
                children: [
                    {
                        category: 'Members Accuracy'
                    }
                    ...
                ]
            }
            ...
        ]
    }, {
    category: 'TS'
 }]

标签: javascriptarraysgroup-bylodash

解决方案


我同意最好的解决方案是重构底层数据源以返回更有用的结果。

但除非您可以使用简单的嵌套reduce()调用。

我正在对每个顶级类别的子键进行排序,以避免依赖对象属性排序,并假设每个元素都以顶级category.

const
  input = [{ category: 'CS', sub_category_1: null, sub_category_2: null }, { category: 'TS', sub_category_1: null, sub_category_2: null }, { category: 'CS', sub_category_1: 'Accuracy', sub_category_2: null }, { category: 'CS', sub_category_1: 'Accuracy', sub_category_2: 'Members Accuracy' }],

  tree = Object.values(
    input.reduce((acc, { category, ...children }) => {
      acc[category] ??= { category, children: [] };

      // sort child keys so as to not rely on object property ordering
      const subcategories = Object.entries(children).sort(([a], [b]) => a.localeCompare(b));

      // reduce child keys into category
      subcategories.reduce((_acc, [, subcategory]) => {
        if (subcategory === null) return _acc;

        let sub = _acc.children.find(({ category }) => category === subcategory);
        if (!sub) {
          sub = { category: subcategory, children: [] };
          _acc.children.push(sub);
        }
        return sub
      }, acc[category]);

      return acc;
    }, {})
  );


console.log(JSON.stringify(tree, null, 2));
.as-console-wrapper { max-height: 100% !important; top: 0; }


推荐阅读