简体   繁体   English

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

[英]how to rescursively deep merge an array of objects

I want to merge two arrays of objects. 我想合并两个对象数组。 Those objects have the same structure, but one of them is missing the hide property. 这些对象具有相同的结构,但是其中之一缺少hide属性。 I want to copy the value of hide property from one object to the other that is missing this property. 我想将hide属性的值从一个对象复制到另一个缺少此属性的对象。 The important part is that I don't want to mutate any of these arrays! 重要的是,我不想突变任何这些阵列!

The first array looks like this (notice that there is hide property): 第一个数组如下所示(注意,这里有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
                    }
                ]
            }
        ]
    }
]

The second array looks almost the same! 第二个数组看起来几乎一样! The only thing missing is hide property. 唯一缺少的是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,
                    }
                ]
            }
        ]
    }
]

Now, I want to create new array with where within each object there is hide property. 现在,我想创建一个新数组,其中每个对象中都有hide属性。

I know how to do this recursively in the imperative way, but unfortunately I'm mutating data - which I don't want to do. 我知道如何以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
}

Now I can create new array with merged objects: 现在,我可以创建带有合并对象的新数组:

const newArray = getHideProperty(second_array, first_array)

Now, every object in second_array has hide property. 现在,second_array中的每个对象都具有hide属性。 But I mutated the array :( 但是我改变了数组:(

How to achieve such result without mutating the array? 如何在不更改数组的情况下实现这种结果?

You'll need to: 您需要:

  1. Create a new array to store the new information, and return that 创建一个新数组来存储新信息,并返回

  2. Deep-copy second[i] to store in the new array, prior to modifying anything 在修改任何内容之前,对second[i]进行深拷贝以存储在新阵列中

For #2, choose your favorite answer from What is the most efficient way to deep clone an object in JavaScript? 对于#2,请从“在JavaScript中深度克隆对象的最有效方法是什么”中选择最喜欢的答案

For #1, very roughly (see comments): 对于#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;
}

This is not meant to be an all-singing, all-dancing solution. 这并不是一个全力以赴的解决方案。 It's meant to help you along the way. 它旨在为您提供全程帮助。 Note the deepCopy placeholder for your preferred solution to #2. 注意您对#2的首选解决方案的deepCopy占位符。 :-) :-)


If you do something like the above (nested loops) and find that it's a performance problem, you can create a Map of the entries in first keyed by their names, and then look them up in the map when looping through second (rather than the nested loop). 如果你这样做上述(嵌套循环),并发现它的性能问题,您可以创建一个Map中的条目的first由他们的名字键,然后看看他们在地图上通过循环时, second (而不是嵌套循环)。 The complexity is only useful if you run into a performance problem with the simple nested loops solution. 您使用简单的嵌套循环解决方案遇到性能问题时,复杂性才有用。

This is a functional approach that doesn't mutate any of the original arrays or their items: 这是一种不改变任何原始数组或其项目的功能方法:

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) } 
            : {}
        );
    });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM