Reputation: 2562
I currently have two objects that look like the following:
const initialValues= { name: "Robert Terrell", email: "[email protected]" }
const formData = { name: 'New Name', email: 'new email' }
I am attempting to compare the two objects with the same keys. I would like to take the initialValues and use them as a reference to compare against the formData. If the formData has different values pertaining to a particular key I would like to return those key value pairs from formData. in this case, both name: 'New Name' and email: 'new email' would be returned. I'm having trouble really wrapping my mind around how to get into a deep comparison of the two objects. I know I can loop through each object and grab their key value pairs using a for loop like so:
for (const [key, value] of Object.entries(object1)) {
console.log(`${key}: ${value}`);
}
but in regards to comparing the key value pairs I'm a bit stuck. any and all suggestions would be much appreciated.
Upvotes: 0
Views: 630
Reputation: 13417
A more generic approach must consider deeply nested data structures. In such cases, comparisons need to be based on the key path of each leaf node’s value. To maintain generality, the result of the diff operation should capture not only changes in values but also indicate newly added or deleted data.
To achieve this, a diff function would be implemented based on sets of key paths. Each key path is generated through a mapping process that recursively flattens the data structure, treating each key as the identifier for the associated value’s path within the object.
const initialValues = {
name: "Robert Terrell",
email: "[email protected]",
};
const formData = {
name: 'New Name',
email: 'new email',
}
console.log({
diff: diffDataValuesByKeypath(initialValues, formData),
});
const oldObject = {
name: 'John',
age: 30,
friends: [
'ali',
'qasim', {
foo: 'Foo',
'foo bar': {
baz: 'Baz',
biz: 'Biz',
},
},
],
};
const newObject = {
name: 'John',
age: 35,
city: 'New York',
friends: [
'ali',
'haider', {
'foo bar': {
baz: 'BAZ',
},
foo: 'Foo',
},
],
};
const diff = diffDataValuesByKeypath(oldObject, newObject);
console.log({ oldObject, newObject, diff });
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
function concatKeypath(keypath, key) {
// - test for a key which can be used with dot chaining.
// - see ... [https://regex101.com/r/tew8gr/1]
return (/^[_$\p{L}][_$\p{L}\p{N}]*$/u).test(key)
// - concat a dot chained key.
? (!!keypath && `${ keypath }.${ key }` || key)
// - concat a quoted key with square bracket notation.
: `${ keypath }["${ key }"]`;
}
function mapDataStructure(value, keypath = '', map = new Map) {
if (Array.isArray(value)) {
value
.forEach((item, idx) =>
mapDataStructure(item, `${ keypath }[${ idx }]`, map)
);
} else if (value && typeof value === 'object') {
Object
.entries(value)
.forEach(([key, val]) =>
mapDataStructure(val, concatKeypath(keypath, key), map)
);
} else {
map.set(keypath, value);
}
return map;
}
function diffDataValuesByKeypath(recentData, currentData) {
const recentMap = mapDataStructure(recentData);
const currentMap = mapDataStructure(currentData);
const recentPaths = new Set([...recentMap.keys()]);
const currentPaths = new Set([...currentMap.keys()]);
const collidingPaths = recentPaths.intersection(currentPaths);
const uniqueRecentPaths = recentPaths.difference(currentPaths);
const uniqueCurrentPaths = currentPaths.difference(recentPaths);
return {
changed: [...collidingPaths.values()]
.reduce((result, keypath) => {
const recentValue = recentMap.get(keypath);
const currentValue = currentMap.get(keypath);
if (!Object.is(recentValue, currentValue)) {
result[keypath] = {
recent: recentValue,
current: currentValue,
};
}
return result;
}, {}),
deleted: [...uniqueRecentPaths.values()]
.reduce((result, keypath) => {
result[keypath] = recentMap.get(keypath);
return result;
}, {}),
added: [...uniqueCurrentPaths.values()]
.reduce((result, keypath) => {
result[keypath] = currentMap.get(keypath);
return result;
}, {}),
};
}
</script>
Upvotes: 0
Reputation: 1
METHOD 1 ```Deep comparison can be performed between two objects using **lodash.isEqual()**, which returns true if they are equal, and false otherwise. For example: const _ = require("lodash"); let employee1 = {"name":"John", "age":30, "car":null}; let employee2 = '{"name":"John", "age":30, "car":null}'; console.log(_.isEqual(employee1, employee2)); // true METHOD 2 For simpler cases where the objects are shallow and don't contain functions or circular references, **JSON.stringify** can be used. For example: let employee1 = {"name":"John", "age":30, "car":null}; let employee2 = '{"name":"John", "age":30, "car":null}'; console.log(JSON.stringify(employee1) === JSON.stringify(employee2)); // true
Upvotes: 0
Reputation: 782785
Loop through one object, then compare its values with the corresponding element of the other.
const initialValues= { name: "Robert Terrell", email: "[email protected]" };
const formData = { name: 'New Name', email: 'new email' };
for (const [key, value] of Object.entries(initialValues)) {
if (value != formData[key]) {
console.log(`${key}: ${value} != ${formData[key]}`);
}
}
Upvotes: 2