【问题标题】:How to union complex objects in javascript?如何在javascript中合并复杂对象?
【发布时间】:2013-01-07 22:44:00
【问题描述】:

我有 3 个不同的对象(obj1,2,3),如下所示,我正在尝试形成 finalObj,它是 3 个对象的联合(唯一树列表)..

我不确定实现这一目标的最佳方法是什么..

编辑:文本是这里的关键。如果已经存在具有相同文本的父节点,我们只需忽略并移动到其子节点并检查该子节点是否存在,否则将该子节点附加到现有父节点等等...

var obj1 = [{
    text: "TreeRoot",
    items: [
        { text: "Subgroup1"},
        { text: "Subgroup2"}
    ]
}]

var obj2 = [{
    text: "TreeRoot",
    items: [
        { text: "Subgroup3"}
    ]
}]

var obj3 = [{
    text: "Subgroup3",
    items: [{
        text: "subgroup5",
        items: [{
            text: "subgroup6",
            items: [{
                text: "subgroup7",
                items: [{
                    text: "subgroup8"
                }]
            }]
        }]
    }]
}]



var finalObj = [{
    text: "TreeRoot",
    items: [
        { text: "Subgroup1"},
        { text: "Subgroup2"},
        {
            text: "Subgroup3",
            items: [{
                text: "subgroup5",
                items: [{
                    text: "subgroup6",
                    items: [{
                        text: "subgroup7",
                        items: [{
                            text: "subgroup8"
                        }]
                    }]
                }]
            }]
        }
    ]
}]

【问题讨论】:

  • 如何才能知道obj3 中的“Subgroup3”在TreeRoot 之下?所有“根”项都必须进行完整遍历以查看名称是否与任何后代匹配,并且仅当它没有创建新的根条目时?请注意,在上述情况下,合并这些树的顺序会改变结果。
  • 您需要为此进行自定义编码。除了 jQuery merge() 函数(这里几乎与您的需求完全无关)之外,您是否尝试过其他任何方法?
  • [The][1] 此处列出的解决方案解决了我的问题... [1]:stackoverflow.com/questions/14222000/…

标签: javascript jquery object merge treeview


【解决方案1】:
var table = {}; // items by id
function recurse(items) {
    for (var i=0; i<items.length; i++) {
        var item = items[i],
            id = item.text;
        if (id in table) 
            table[id].items = (table[id].items && item.items)
              ? table[id].items.concat(item.items) // merge
              : table[id].items || item.items;
        else
            table[id] = item;
        if (item.items)
            recurse(item.items);
    }
}
recurse(obj1), recurse(obj2), recurse(obj3);

// assuming there are no cycles and only one parent per node in the graph
for (var text in table) (function recurse(text) {
    var items = table[text].items;
    if (!items) continue;
    for (var i=0; i<items.length; i++) {
        var id = items[i].text;
        if (id in table) {
            items[i] = table[id];
            recurse(id);
            delete table[id];
        }
    }
})(text);

// now, table consists only of the root keys (should be only one):
for (var id in table)
    var finalObj = table[id];

【讨论】:

    【解决方案2】:

    这里的诀窍是以利用 javascript 对象的自然特征并促进合并的方式构造对象。

    obj1obj2obj3 中的所有数组都是多余的,因为它们每个都包含不超过一项。

    不要使用属性textitems 构造对象,而是使用文本作为键,将项目作为其属性,从而提供更紧凑的数据结构。

    var obj1 = {
        "Subgroup1": null,
        "Subgroup2": null
    };
    var obj2 = {
        "Subgroup3": null
    };
    var obj3 = {
        "Subgroup3": {
            "subgroup5": {
                "subgroup6": {
                    "subgroup7": {
                        "subgroup8": null
                    }
                }
            }
        }
    };
    

    现在您可以使用 jQuery 的$.extend() 功能了。

    var finalObj = $.extend(true, {}, obj1, obj2, obj3);
    

    给出:

    var finalObj = {
        "Subgroup1": null,
        "Subgroup2": null,
        "Subgroup3": {
            "subgroup5": {
                "subgroup6": {
                    "subgroup7": {
                        "subgroup8": null
                    }
                }
            }
        }
    };
    

    与您的原始文件相比,几乎不会丢失任何信息。发生的损失是Subgroup1Subgroup2Subgroup3order,它们现在是 finalObj 的无序属性,而不是数组的有序元素。同样,如果在任何级别有多个子组,它们也将是无序的。

    • 如果您能忍受这种限制,那么上述方法将为您省去很多心痛。
    • 如果您不能忍受这种约束,那么稍加考虑,仍然可以按正确的顺序提取子组。

    【讨论】:

    • 很好的简化。不过,我认为实际的损失是您不能将这种方法用于具有比标识符和子节点更多属性的树节点。
    • 在原始数据模型中,OP 可以轻松地将其他属性添加到节点对象,例如“颜色”、“位置”或“文本”和“项目”旁边的任何内容。这对于紧凑的结构是不可能的,而且 imo 比失去订单更不利。
    • @Bergi,对不起,我不同意。当然,在任何级别上,每个对象都可以包含除子组之外的其他属性吗?虽然我明白你在说什么。
    • 所以您建议对属性使用命名约定,例如“以subgroup… 开头的所有内容都被视为子节点,而其他属性则不是”?我不认为这是一个好主意。虽然在受限环境中是可能的,但它至少会是一个严重的约束。由于 OP 有一个名为“TreeRoot”的节点,我认为它不适用于此处。
    • 另一点:在我看来,OP 宁愿拥有像 obj1 = {"TreeRoot": {"Subgroup1":null, "Subgroup2":null}}; obj2 = {"TreeRoot": {"Subgroup3":null}}; obj3 = {"Subgroup3":…}; 这样的结构 - 他的问题是这三个对象位于树的不同级别(特别是 obj3 在这里)。一个简单的$.extend 合并是不够的。
    【解决方案3】:

    不确定这是否是合并树对象的正确方法,但只是想得到您的反馈/建议...

    我有一个递归函数,它根据 id 返回节点。我检查 parent id 和 child id ,如果 parent id 存在但找不到 child id 我将孩子添加到 parent。如果父 ID 不存在我创建一个新节点,如果孩子已经退出,我只是忽略那个孩子...

    这样,我可以联合我的节点(通过循环)...欢迎提出建议!!!!

             var arrayObject=[];
    
                var ob =    {
                    text: "root",
                    id: 1,
                    items: [
                        {
                            text: "child one",
                            id: 11,
                            items: [
                                {
                                    text: "grand child 1",
                                    id: 111,
                                    items: []},
                                {
                                    text: "grand child 2",
                                    id: 112,
                                    items: []}
                            ]},
                        {
                            text: "child two",
                            id: 12,
                            items: []}
                    ]
                };
    
                function findObjectById(root, id) {
                    if (root.items) {
                        for (var k in root.items) {
                            if (root.items[k].id == id) {
                                return root.items[k];
                            }
                            else if (root.items.length) {
                                return findObjectById(root.items[k], id);
                            }
                        }
                    }
                };
                var newChild={
                    text: "child x",
                    id: 115,
                    items: []
                };
    
                for(var i=0;i<2;i++){
                    if(i==0){
                        var checkParent = findObjectById(ob, 11);
                        alert(JSON.stringify(checkParent));
    
                    }else{
                        var checkParent = findObjectById(ob, 116);
                    }
                    if(checkParent) {
                        var checkChild=findObjectById(checkParent, newChild.id);
                        alert(JSON.stringify(checkChild));
                        if(!checkChild){
                            checkParent.items.push(newChild);
                        }
                        arrayObject.push(ob)
                    }else{
    
                        arrayObject.push(newChild);
                    }
                }
    

    【讨论】:

      猜你喜欢
      • 2022-06-14
      • 2014-09-12
      • 1970-01-01
      • 2018-01-04
      • 2017-07-26
      • 1970-01-01
      • 2020-06-23
      • 2016-10-03
      • 2013-10-09
      相关资源
      最近更新 更多