如何递归深度合并一个对象数组

时间:2017-07-10 17:41:12

标签: javascript dictionary filter functional-programming reduce

我想合并两个对象数组。这些对象具有相同的结构,但其中一个缺少hide属性。我想将hide属性的值从一个对象复制到另一个缺少此属性的对象。重要的是我不想改变任何这些数组!

第一个数组看起来像这样(注意有hide属性):

let first_array = [
    {
        name: 'John',
        age: 40,
        hide: true,
        childs: [
            {
                name: 'Alice',
                age: 20,
                hide: false,
                childs: [
                    {
                        name: 'Mike',
                        age: 2,
                        hide: true
                    }
                ]
            }
        ]
    },
    {
        name: 'Peter',
        age: 40,
        hide: true,
        childs: [
            {
                name: 'Andrew',
                age: 20,
                hide: true,
                childs: [
                    {
                        name: 'Jessica',
                        age: 2,
                        hide: true
                    }
                ]
            }
        ]
    }
]

第二个阵列看起来几乎一样!唯一缺少的是hide属性。

let second_array = [
    {
        name: 'John',
        age: 40,
        childs: [
            {
                name: 'Alice',
                age: 20,
                childs: [
                    {
                        name: 'Mike',
                        age: 2,
                    }
                ]
            }
        ]
    },
    {
        name: 'Peter',
        age: 40,
        childs: [
            {
                name: 'Andrew',
                age: 20,
                childs: [
                    {
                        name: 'Jessica',
                        age: 2,
                    }
                ]
            }
        ]
    }
]

现在,我想创建一个新数组,其中每个对象中都有hide属性。

我知道如何以imperative的方式递归地执行此操作,但不幸的是我正在改变数据 - 我不想这样做。

function getHideProperty(first, second) {
    for (let i = 0; i < second.length; i++) {
        for (let j = 0; j < first.length; j++) {
            if (second[i].name === first[j].name) {
                second[i].hide = first[j].hide
                if (second[i].childs) {
                    second[i].childs = getHideProperty(first[j].childs, second[i].childs)
                }
            }
        }
    }
    return second
}

现在我可以使用合并对象创建新数组:

const newArray = getHideProperty(second_array, first_array)

现在,second_array中的每个对象都有hide属性。但是我改变了阵列:(

如何在不改变数组的情况下实现这样的结果?

2 个答案:

答案 0 :(得分:2)

你需要:

  1. 创建一个新数组来存储新信息,然后返回

  2. 在修改任何内容之前,深层复制second[i]以存储在新数组中

  3. 对于#2,请从What is the most efficient way to deep clone an object in JavaScript?

    中选择您最喜欢的答案

    对于#1,非常粗略(见评论):

    function getHideProperty(first, second) {
        const result = []; // Our result array
        for (let i = 0; i < second.length; i++) {
            const secondEntry = result[i] = deepCopy(second[i]); // The deep copy, and let's avoid constantly re-retrieving second[i]/result[i]
            for (let j = 0; j < first.length; j++) {
                if (secondentry.name === first[j].name) {
                    secondentry.hide = first[j].hide
                    if (secondEntry.childs) {
                        // Could be more efficient here, since the entries in `childs` are already copies; left as an exercise to the reader...
                        secondEntry.childs = getHideProperty(first[j].childs, secondEntry.childs)
                    }
                }
            }
        }
        return result;
    }
    

    这并不是一个全能的,全能的舞蹈解决方案。这是为了帮助您一路走来。请注意deepCopy占位符,以获得#2的首选解决方案。 : - )

    如果您执行上述操作(嵌套循环)并发现这是性能问题,您可以在Map中创建first个按名称键入的条目,然后查找它们在循环second(而不是嵌套循环)时在地图中。只有如果使用简单的嵌套循环解决方案遇到性能问题,复杂性才有用。

答案 1 :(得分:1)

这是一种功能性方法,不会改变任何原始数组或其项目:

function getHideProperty(first, second) {
    return second.map(function(item) {
        var corresponding = first.find(function(searchItem) {
            return searchItem.name === item.name;
        });
        return Object.assign({},
          item,
          { hide: corresponding.hide },
          item.childs
            ? { childs: getHideProperty(item.childs, corresponding.childs) } 
            : {}
        );
    });
}