【问题标题】:Recursively creating a JSON tree, adding only at the deepest level递归创建 JSON 树,仅在最深层次添加
【发布时间】:2017-07-27 14:09:20
【问题描述】:

我想创建一个未知对象的JSON层次结构,所以必须递归处理。

这是我的函数,其中angular.element.isEmptyObject() 继承自 jQuery,angular.copy() 是一个创建对象深层副本的函数(我使用的是AngularJS)。

function recurseTree(tree, newKey, newId) {
    if(angular.element.isEmptyObject(tree)) {
        tree[newKey] = {_id: newId};
    } else {
        for(var key in tree) {
            if(typeof tree[key] == 'object') recurseTree(tree[key], newKey, newId);
            else tree[newKey] = {_id: newId};
        }
    }
    return angular.copy(tree);
}

现在运行这个:

var testT = {};
console.log(recurseTree(testT, 'a', '1'));
console.log(recurseTree(testT, 'b', '2'));
console.log(recurseTree(testT, 'c', '3'));
console.log(recurseTree(testT, 'd', '4'));
console.log(recurseTree(testT, 'e', '5'));

您会注意到第一个和第二个按预期返回:

{ 
    a: { 
        _id: '1',
        b: {
            _id: '2'
        }
    }
}

但是第三个是我遇到麻烦的地方。

{ 
    a: { 
        _id: '1',
        b: {
            _id: '2',
            c: {
                _id: '3'
            }
        },
        c: {
            _id: '3'
        }
    }
}

我需要解决什么问题才能将c 对象附加为ONLY 作为b 的子对象,而不是作为a 的子对象?我被难住了。

这是一个运行中的 JSFiddle,请检查您的控制台以获取结果。 http://jsfiddle.net/winduptoy/Mjq5D/2/

【问题讨论】:

  • 你能把工作的jsfiddle.net 和所有的依赖库放在一起吗?
  • 哎呀,抱歉我忘记了,我把它加到问题的底部了。

标签: javascript recursion


【解决方案1】:

试试这个:

function recurseTree(tree, newKey, newId) {
    if(angular.element.isEmptyObject(tree)) {
        tree[newKey] = {_id: newId};
        return;
    } 

    var child = null; // find current tree's child
    for(var key in tree) {
        if (key != '_id') {
            child = tree[key]; // found a child
            break;
        }
    }
    if (child) { // recursively process on child
        recurseTree(child, newKey, newId);
    } else { // no child, so just fill the tree
        tree[newKey] = {_id: newId};
    }
}

测试:

var testT = {};
recurseTree(testT, 'a', '1');
console.log(testT);  
recurseTree(testT, 'b', '1');
console.log(testT); 
recurseTree(testT, 'c', '1');
console.log(testT); 
recurseTree(testT, 'd', '1');
console.log(testT); 
recurseTree(testT, 'e', '1');
console.log(testT);

请注意,出于性能考虑,我没有使用angular.copy(tree)。 如果您不想更改树,请在将其传递给函数recurseTree 之前将其复制。请在jsFiddle 上试用。

【讨论】:

  • 非常感谢,这是正确的。你还解决了我的另一个问题。如果您还要在此处发布此代码,我将接受您的回答。 stackoverflow.com/questions/14088181/…
  • 不客气,我按照您的要求回答了这个问题。
【解决方案2】:

试试看?有必要用for loop吗?

for(var key in tree) {
   if(typeof tree[key] == 'object'){ 
       recurseTree(tree[key], newKey, newId);
       break;
   }
   else {
       tree[newKey] = {_id: newId};
       break;
   }
}

【讨论】:

  • 在那里添加breaks 修复了它,但你能解释一下我如何在没有for循环的情况下做到这一点吗?
  • @WindUpToy 在您发布的情况下,新节点始终添加到该树级别的第一个子节点。所以我说没必要用for loop
  • 回是正确的,这并不完全正确。他的代码现在是公认的答案。
  • @HuiZheng,@Wind Up Toy我只是找出逻辑错误,并在测试前发布,如果有更好的答案,请接受。
【解决方案3】:

我的解决方案:

vm.getChilds = function (data, parent_id) {
        return _.filter(data, function (item) {
            return item.parent_id == parent_id;
        });
    };
    vm.getIds = function (arr) {
        var ids = [];
        arr.forEach(function (item) {
            ids.push(item.id);
        });
        return ids;
    };
    vm.updateList = function (data, arr) {
        var ids = vm.getIds(arr);
        var result = [];
        data.forEach(function (item) {
            if (ids.indexOf(item.id) == -1) {
                result.push(item);
            }
        });
        return result;
    };
    vm.getThree = function (data, parent_id) {
        var items = vm.getChilds(data, parent_id);
        if (items.length == 0) return null;
        var tree = [];
        var newData = vm.updateList(data, items);
        items.forEach(function (item) {
            item.sub_departments = vm.getThree(newData, item.id);
            tree.push(item);
        });
        return tree;
    };

【讨论】:

    猜你喜欢
    • 2013-08-04
    • 1970-01-01
    • 1970-01-01
    • 2019-12-18
    • 2012-03-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多