Javascript 如何重新搜索深度合并对象数组

Javascript 如何重新搜索深度合并对象数组,javascript,dictionary,filter,functional-programming,reduce,Javascript,Dictionary,Filter,Functional Programming,Reduce,我想合并两个对象数组。这些对象具有相同的结构,但其中一个缺少“隐藏”属性。我想将hide属性的值从一个对象复制到缺少此属性的另一个对象。重要的是,我不想改变这些数组中的任何一个 第一个数组如下所示(请注意,有一个隐藏属性): 第二个数组看起来几乎一样!唯一缺少的是隐藏属性 let second_array = [ { name: 'John', age: 40, childs: [ {

我想合并两个对象数组。这些对象具有相同的结构,但其中一个缺少“隐藏”属性。我想将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,
                    }
                ]
            }
        ]
    }
]
现在,我想创建一个新数组,其中每个对象中都有隐藏属性

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,
                    }
                ]
            }
        ]
    }
]
我知道如何以
命令式
的方式递归地执行此操作,但不幸的是,我正在改变数据-我不想这样做

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
}
现在,第二个数组中的每个对象都有隐藏属性。但我改变了数组:(

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

您需要:

  • 创建一个新数组来存储新信息,并返回

  • 在修改任何内容之前,深度复制
    second[i]
    以存储在新阵列中

  • 对于#2,请从中选择您最喜欢的答案

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

    函数getHideProperty(第一、第二){ const result=[];//我们的结果数组 for(设i=0;i 这并不是一个全歌唱、全舞蹈的解决方案。它是为了帮助您。请注意
    deepCopy
    占位符,它是您首选的#2.:-)



    如果您执行类似于上述操作(嵌套循环)并发现这是一个性能问题,那么您可以先创建
    中条目的
    映射
    ,然后在
    第二个
    (而不是嵌套循环)中循环时在映射中查找它们。这种复杂性只有在使用简单嵌套循环解决方案时遇到性能问题时才有用。

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

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

    当然,从技术上讲,你并没有改变数组。您正在改变数组引用的对象。这在考虑解决方案时很重要。通过变异,我的意思是,在开始时,某个数组的值是X,在将其传递给函数后,该数组的值不再是X。该数组经过了变异,同样,它不是(数组中的值——对对象的引用——在您的示例中没有改变),但这只在帮助了解需要什么来避免它时才重要:创建新对象(和新数组)。:-)哇!非常感谢您的帮助和提示。我使用Object.assign作为deepCopy,它就像一个符咒。是的,我是在改变数组中的对象,而不是数组本身。我会考虑使用地图here@sympi:请注意
    对象.assign
    不是深度复制,因此不会复制任何从属对象(例如
    child
    数组),而是共享它们。Mikael的回答通过为新对象提供一个新的
    childs
    属性来避免这个问题,这对于您声明的数据来说是很好的;但是,除非你对所有从属对象都明确地这样做,否则你会得到丑陋的相声。嗯,所以这实际上是非常奇怪的。在我的真实数据中,有9个级别的深度,我正在使用对象扩散(最终被传输到object.assign?)进行复制,它看起来工作得很好。@sympi:如果有多个级别就可以了,反正你正在替换
    childs
    。问题是,如果这些对象上有另一个从属对象,而您没有替换它。也许你现在不知道;但是如果你以后再添加一个,你可能不会想回去解决这个问题,然后你会在新旧数据之间得到丑陋的交叉引用。好的,再次感谢你的帮助!我将使用lodashIt中的cloneDeep,但是它是脆弱的(对结构的轻微更改会导致新数组引用旧对象的一部分),并且需要创建大量额外的临时对象。
    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;
    }
    
    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) } 
                : {}
            );
        });
    }