javascript - 使用 lodash 从平面列表创建树

标签 javascript tree lodash

我正在尝试使用下面的 json 对象数组创建类别树。 如果一个类别的父级等于另一个类别的 ID,我想将一个类别设置为另一个类别的子级,并且我希望帖子也成为该类别的子级,而不是为帖子设置单独的字段,我将添加一个标志字段是否为类别 isParent

它看起来工作正常,但如您所见,如果一个类别同时有类别和帖子作为子类别,它只会显示类别。另一个问题是,如果帖子的数组中有空值,它仍会将它们作为子项推送。

我的代码中有什么错误,或者是否有更简单或更好的解决方案?

var tree = unflatten(getData());
var pre = document.createElement('pre');
console.log(tree);
pre.innerText = JSON.stringify(tree, null, 4);

document.body.appendChild(pre);

function unflatten(array, parent, tree) {
  tree = typeof tree !== 'undefined' ? tree : [];
  parent = typeof parent !== 'undefined' ? parent : {
    id: 0
  };
  _.map(array, function(arr) {
    _.set(arr, 'isParent', true);
  });
  var children = _.filter(array, function(child) {
    return child.parent == parent.id;
  });

  if (!_.isEmpty(children)) {
    if (parent.id == 0) {
      tree = children;
    } else {
      parent['children'] = children;
    }
    _.each(children, function(child) {
      var posts = _.map(child.posts, function(post) {
        return _.set(post, 'isParent', false);
      });
      child['children'] = posts;
      delete child.posts;
      unflatten(array, child);
    });
  }

  return tree;

}

function getData() {
  return [{
    "id": "c1",
    "parent": "",
    "name": "foo",
    "posts": [{
      "id": "p1"
    }]
  }, {
    "id": "c2",
    "parent": "1",
    "name": "bar",
    "posts": [{
      "id": "p2"
    }]
  }, {
    "id": "c3",
    "parent": "",
    "name": "bazz",
    "posts": [
      null
    ]
  }, {
    "id": "c4",
    "parent": "3",
    "name": "sna",
    "posts": [{
      "id": "p3"
    }]
  }, {
    "id": "c5",
    "parent": "3",
    "name": "ney",
    "posts": [{
      "id": "p4"
    }]
  }, {
    "id": "c6",
    "parent": "5",
    "name": "tol",
    "posts": [{
      "id": "p5"
    }, {
      "id": "p6"
    }]
  }, {
    "id": "c7",
    "parent": "5",
    "name": "zap",
    "posts": [{
      "id": "p7"
    }, {
      "id": "p8"
    }, {
      "id": "p9"
    }]
  }, {
    "id": "c8",
    "parent": "",
    "name": "quz",
    "posts": [
      null
    ]
  }, {
    "id": "c9",
    "parent": "8",
    "name": "meh",
    "posts": [{
      "id": "p10"
    }, {
      "id": "p11"
    }]
  }, {
    "id": "c10",
    "parent": "8",
    "name": "ror",
    "posts": [{
      "id": "p12"
    }, {
      "id": "p13"
    }]
  }, {
    "id": "c11",
    "parent": "",
    "name": "gig",
    "posts": [{
      "id": "p14"
    }]
  }, {
    "id": "c12",
    "name": "xylo",
    "parent": "",
    "posts": [{
      "id": "p15"
    }]
  }, {
    "id": "c13",
    "parent": "",
    "name": "grr",
    "posts": [{
      "id": "p16"
    }, {
      "id": "p17"
    }, {
      "id": "p14"
    }, {
      "id": "p18"
    }, {
      "id": "p19"
    }, {
      "id": "p20"
    }]
  }]
}
<script src="//cdn.jsdelivr.net/lodash/3.10.1/lodash.min.js"></script>

预期输出

所以预期的输出将更像:

[
   {
       id: 'c1',
       isParent: true,
       children: [
          {
             id: 'c2',
             isParent: true,
             children: []
          },
          {
             id: 'p1'
             isParent: false
          }
       ]
   }
]

等等..

最佳答案

您的代码非常重要。尝试着眼于数据流的“全局”,而不是通过反复试验来编写代码。这更难,但你会得到更好的结果(而且,事实上,通常它更快):)

我的想法是先按 parent 对类别进行分组。这是我的解决方案的第一行,之后实际上变得容易多了。

_.groupBy_.keyBy在这里帮助很多:

function makeCatTree(data) {
    var groupedByParents = _.groupBy(data, 'parent');
    var catsById = _.keyBy(data, 'id');
    _.each(_.omit(groupedByParents, ''), function(children, parentId) {
        catsById['c' + parentId].children = children; 
    });
    _.each(catsById, function(cat) {
        // isParent will be true when there are subcategories (this is not really a good name, btw.)
        cat.isParent = !_.isEmpty(cat.children); 
        // _.compact below is just for removing null posts
        cat.children = _.compact(_.union(cat.children, cat.posts));
        // optionally, you can also delete cat.posts here.
    });
    return groupedByParents[''];
}

我建议在开发者控制台中尝试每个部分,然后它变得容易理解。

关于javascript - 使用 lodash 从平面列表创建树,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32134115/

相关文章:

php - 如何为树结构开发数据库模式(有向无环图)

Haskell - 为树类型创建折叠函数

c++ - 带有 "subtree"的 QTreeWidgetItemIterator

javascript - 选择数据清理的数组值

javascript - html2canvas 基础知识

javascript - ajax请求中的404和401错误

javascript - HTML 如何使用 javascript 函数将输入标记添加到有序列表

javascript - 如何在 JSBin 中导入 lodash?

javascript - 使用 lodash 将数组分为非重复项和仅重复项

javascript - 如何从 ng-repeat 表达式中更新父作用域变量?