Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Lodash to compare and find difference for two complex objects?

I’m trying to learn Lodash right now because I think it could help a lot with my current project. However, I have an issue that I can’t figure out how to solve, and, since I’m a Lodash rookie, I thought I’d post something to see if I could get some guidance.

I have two complex objects (see the structure below) – made using angular.copy(original, copy) (my app is, obviously, an Angular app).

After the copy, both

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
}

After some further processing and changing of property values, I now need to re-sync some of the properties (not all of them) in the copy object back into the original object. Specifically, I need to go thru the entire copy object, find all “widgets”, get the “widgetName” value and the complete “widgetParameters” collection from the widget, then go thru the entire original object, find the exact matching “widget”, and update the matching widget's “widgetName” and “widgetParameters” with the values from the copy object.

I’ve got it working with a brute force approach with lots of forEach’ing (see below), but I’m thinking there is probably a more elegant and efficient way in Lodash to do what I’m trying to do.

// 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);
                        }

                    });
                });
            });

        });
    });
});

Any thoughts, help, ideas, etc.?

Thanks!

like image 757
lmttag Avatar asked Apr 16 '15 22:04

lmttag


People also ask

How do you compare two objects with Lodash?

In Lodash, we can deeply compare two objects using the _. isEqual() method. This method will compare both values to determine if they are equivalent.

How do you compare two values of objects?

Whereas the equals() method compares two objects. Objects are equal when they have the same state (usually comparing variables). Objects are identical when they share the class identity. For example, the expression obj1==obj2 tests the identity, not equality.

How does Lodash isEqual work?

The Lodash _. isEqual() Method performs a deep comparison between two values to determine if they are equivalent. This method supports comparing arrays, array buffers, boolean, date objects, maps, numbers, objects, regex, sets, strings, symbols, and typed arrays.


1 Answers

I have had great success with the JavaScript-based deep-diff utility. For example:

// 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);

If you wanted to apply some changes at the browser level, you could iterate over the changes (differences) and do something like this for each difference received:

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

I don't know of an elegant and easy way to do this in Lodash, without rebuilding the functionality of the deep-diff library.

like image 155
ryanm Avatar answered Oct 22 '22 11:10

ryanm