如何使用Lodash比较和找到两个复杂对象的差异?

时间:2015-04-16 22:39:30

标签: javascript angularjs underscore.js lodash

我正在努力学习Lodash,因为我觉得它对我目前的项目有很大的帮助。但是,我有一个问题,我无法弄清楚如何解决,而且,因为我是一个Lodash新秀,我想我会发布一些东西,看看能不能得到一些指导。

我有两个复杂的对象(参见下面的结构) - 使用angular.copy(原始,复制)制作(我的应用程序显然是一个Angular应用程序)。

复制后,两者

original and copy =
{
    name: 'name',
    date: 'date',
    rows: [  // array of objects
        {
            // this is row 1
            columns: [  // array of objects
                {
                    // this is column 1
                    widgets: [  // array of objects
                        {
                            // this is 1 widget in this column
                            createdDate: 'createdDate1',
                            widgetName: 'widgetName1',
                            widgetParameters: [  // array of objects
                                { parameterName: 'parameterName1', parameterValue: 'parameterValue1' },
                                { parameterName: 'parameterName2', parameterValue: 'parameterValue2' },
                                { parameterName: 'parameterName3', parameterValue: 'parameterValue3' }
                            ]
                        }
                    ]
                },
                {
                    // this is column 2
                    widgets: [
                        {
                            // this is 1 widget in this column
                            createdDate: 'createdDate2',
                            widgetName: 'widgetName2',
                            widgetParameters: [  // array of objects
                                { parameterName: 'parameterName1a', parameterValue: 'parameterValue1a' },
                                { parameterName: 'parameterName2a', parameterValue: 'parameterValue2a' }
                            ]
                        },
                        {
                            // this is 2 widget in this column
                            // ...
                        }
                    ]
                },
                {
                    // this is column 3
                    widgets: [
                        {
                            // this is 1 widget in this column
                            createdDate: 'createdDate3',
                            widgetName: 'widgetName3',
                            widgetParameters: [  // array of objects
                                { parameterName: 'parameterName1b', parameterValue: 'parameterValue1a' }
                            ]
                        },
                        {
                            // this is 2 widget in this column
                            // ...
                        },
                        {
                            // this is 3 widget in this column
                            // ...
                        }
                    ]
                }
            ]  // end columns array
        },
        {
            // this is row 2
            // ... same structure as above with columns, widgets, widgetParameters
        }
    ]  // end rows array
}

经过一些进一步处理和更改属性值后,我现在需要将复制对象中的一些属性(不是所有属性)重新同步回原始对象。具体来说,我需要通过整个复制对象,找到所有“小部件”,从小部件获取“widgetName”值和完整的“widgetParameters”集合,然后通过整个原始对象,找到完全匹配的“小部件” ,并使用复制对象中的值更新匹配小部件的“widgetName”和“widgetParameters”。

我已经开始使用蛮力方法进行大量的forEach'ing(见下文),但我认为Lodash可能有一种更优雅高效的方式来做我正在尝试做的事情

// brute force it
angular.forEach(copy.rows, function (row) {
    angular.forEach(row.columns, function (column) {
        angular.forEach(column.widgets, function (widget) {
            var widgetName = widget.widgetName;
            var createdDate = widget.createdDate;
            var widgetParameters = widget.widgetParameters;

            angular.forEach(original.rows, function (row1) {
                angular.forEach(row1.columns, function (column1) {
                    angular.forEach(column1.widgets, function (widget1) {

                        if ((widgetName === widget1.widgetName) && (createdDate === widget1.createdDate))
                        {
                            widget1.widgetName = widgetName;
                            angular.copy(widgetParameters, widget1.widgetParameters);
                        }

                    });
                });
            });

        });
    });
});

任何想法,帮助,想法等?

谢谢!

2 个答案:

答案 0 :(得分:4)

我使用基于JavaScript的deep-diff实用程序取得了巨大成功。例如:

// this would be a node.js way to require it, or you could use the DeepDiff object in the browser's global window object
var diff = require('deep-diff').diff;
var differences = diff(original, copy);

如果您想在浏览器级别应用某些更改,您可以迭代更改(差异)并针对收到的每个差异执行类似的操作:

DeepDiff.applyChange(original, {}, difference);

我不知道在Lodash中执行此操作的优雅而简单的方法,而无需重建deep-diff库的功能。

答案 1 :(得分:1)

你可以做的是构建一个只包含你想要保留的东西的小对象,让它称之为diffObject,所以你只需要这样做:

// Puts the diff back into the original object
_.merge( originalObject, diffObject );

现在要构建这样的diff对象,你可能仍然需要浏览所有对象,或者有一些聪明的递归构建函数来跟踪它经历的路径和所有对象。