V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
s609926202
V2EX  ›  问与答

关于 Javascript 递归问题,我懵逼了,,,

  •  
  •   s609926202 · 2017-12-03 17:42:28 +08:00 · 2504 次点击
    这是一个创建于 2336 天前的主题,其中的信息可能已经有所发展或是发生改变。

    API 返回的 json 数据: [ { id: 3, post: 73, parent: 2 }, { id: 2, post: 73, parent: 0 } ]

    目标是: [ { id: 2, post: 73, parent: 0, children: [ { id: 3, post: 73, parent: 2 } ], } ]

    这是我写的递归(在微信小程序的 util.js 里): function rebuildArray(data = [], parent = 0) { var rebuildData = [];

    for (var i = 0; i < data.length; i++) {
    	if (data[i].parent === parent) {
    		data[i]['children'] = data[i];
    	} else {
    		rebuildArray(data[i], data[i].parent);
    	}
    
    	rebuildData = data[i];
    }
    
    return rebuildData;
    

    }

    但是结果是错误的。。。

    第 1 条附言  ·  2017-12-03 19:42:32 +08:00

    我改了一下逻辑,每次循环data,判断当前数组parent为0时,赋值给rebuildData,否则,如果当前数组parent等于函数的传值parent时,把当前数组push到rebuildData里,否则进行下一次循环,如下,但是我在小程序里运行时,他报错提示Cannot read property 'push' of undefined。。。

    function rebuildArray (data = [], parent = 0) {
    	if (data === null) {
    		return;
    	}
    
    	var rebuildData = {};
    
    	for (var i = 0; i < data.length; i++) {
    		if (data[i].parent == 0){
    			rebuildData[i] = data[i];
    		} else {
    			if (data[i].parent === parent) {
    				rebuildData[i].push({'children': data[i]});
    			} else {
    				rebuildArray(data, data[i].parent);
    			}
    		}
    	}
    
    	return rebuildData;
    }
    
    第 2 条附言  ·  2017-12-04 22:05:23 +08:00

    这是我最后的解决方案,无奈只能用两个函数来实现:

    const getSonsTree = function (obj, data) {
    	var children = new Array();
    
    	for (var i = 0; i < data.length; i++) {
    		if (data[i].parent == obj.id) {
    			getSonsTree(data[i], data);
    			children.push(data[i]);
    		}
    	}
    
    	if (children.length > 0) {
    		obj.children = children;
    	}
    
    	return obj;
    }
    
    const buildTree = function (data = {}) {
    	var ptree = [];
    
    	for (var i = 0; i < data.length; i++) {
    		if (data[i].parent === 0) {
    			var o = getSonsTree(data[i], data);
    			ptree.push(o);
    		}
    	}
    
    	return ptree;
    }
    

    然后把后端返回 json 放进 buildTree 里就行了: console.log(buildTree(data));

    实现了 。。。

    10 条回复    2017-12-04 22:03:45 +08:00
    per
        1
    per  
       2017-12-03 18:04:01 +08:00
    如果数据里面有一条数据, 它既不是某一项的 child, 也不是某一项的 parent. 你要怎么处理?
    s609926202
        2
    s609926202  
    OP
       2017-12-03 18:10:02 +08:00
    @per 不会出现这种情况的,我这个源数据是评论数据,,只有要么是顶级数据,要是是节点下的回复数据,也就是说 parent 不为 0
    geelaw
        3
    geelaw  
       2017-12-03 18:17:46 +08:00   ❤️ 1
    我的神呐……您这个效率太低了,而且明明有非常简单的高效写法的。

    第一步给所有的元素加上 .children = []
    第二步按照 id 排序
    第三步把每个元素 push 进它 parent 的 children 里面
    第四步删除每个 children 为空数组的元素的 children 属性,并顺便把其他的元素收集起来

    时间是 nlogn。

    此外,您的代码没有贴对,让人很难受。
    longear
        4
    longear  
       2017-12-03 19:26:38 +08:00
    下面这两行的逻辑不对,parent 只是一个数字, 按照你的逻辑 只要相等,就让 data[i] 的 children 指向自身,这就说不通, 输出结果自然不对。
    if (data[i].parent === parent) {
    data[i]['children'] = data[i];


    可以分解为两三个独立的函数,逻辑上就简单很多。
    longear
        5
    longear  
       2017-12-03 19:36:21 +08:00
    var apiData = [ { id: 3, post: 73, parent: 2 }, { id: 2, post: 73, parent: 0 } ];

    function findParent(data, parent){
    for(var i=0; i<data.length; i++){
    if(data[i].id == parent){
    return data[i];
    }
    }
    return [];
    }

    function preProcess(data){
    for (var i = 0; i < data.length; i++) {
    findParent(data, data[i].parent)['children'] = data[i];
    }
    }


    function rebuildArray(data = [], parent = 0) {
    for (var i = 0; i < data.length; i++) {
    if(data[i]['parent'] == 0){ // 找到根元算
    return data[i];
    }
    }
    }

    preProcess(apiData);
    console.log(rebuildArray(apiData));
    luguokong
        6
    luguokong  
       2017-12-03 19:54:03 +08:00
    var rebuildData = {};
    对象没有 push 方法
    s609926202
        7
    s609926202  
    OP
       2017-12-03 20:08:29 +08:00
    @luguokong 改成[]也报同样的错,,,
    lwbjing
        8
    lwbjing  
       2017-12-04 09:31:21 +08:00
    哥你没发现你的方法一执行,你的对象就重置了吗。。
    s609926202
        9
    s609926202  
    OP
       2017-12-04 09:54:19 +08:00
    @lwbjing 确实,,如果是 php 就好了,,还有引用
    s609926202
        10
    s609926202  
    OP
       2017-12-04 22:03:45 +08:00
    这是我最后的解决方案,无奈只能用两个函数来实现:
    ```
    const getSonsTree = function (obj, data) {
    var children = new Array();

    for (var i = 0; i < data.length; i++) {
    if (data[i].parent == obj.id) {
    getSonsTree(data[i], data);
    children.push(data[i]);
    }
    }

    if (children.length > 0) {
    obj.children = children;
    }

    return obj;
    }

    const buildTree = function (data = {}) {
    var ptree = [];

    for (var i = 0; i < data.length; i++) {
    if (data[i].parent === 0) {
    var o = getSonsTree(data[i], data);
    ptree.push(o);
    }
    }

    return ptree;
    }
    ```

    然后把后端返回 json 放进 buildTree 里就行了:
    ```
    console.log(buildTree(data));
    ```

    实现了
    。。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2748 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 05:22 · PVG 13:22 · LAX 22:22 · JFK 01:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.