Reputation: 403
I am trying to compare two object arrays for equality, disregarding any differences in the order of the properties. I just want to know when the values for each property match. Below are examples of one object in each array being compared, that should be equal, based on the values of each property. The ordering of the properties does not matter, along with the ordering of the "values" property values.
{ "fieldId": "123456789",
"operationType": 1,
"definitionType": 1,
"values": ["123","456"],
"isAllSelected": false,
"dateRangeSelectionType": 0
}
{ "isAllSelected": false,
"operationType": 1,
"definitionType": 1,
"fieldId": "123456789",
"values": ["456","123"],
"dateRangeSelectionType": 0
}
I have attempted to use JSON.stringify to compare these arrays, but I know this won't work since it will take the ordering into account of equality.
I also have the following helper functions that I am using for another object array, however this does not work properly for these arrays:
> const objectsAreEqual = (object1: any, object2: any) =>
> Object.keys(object1).length === Object.keys(object2).length
> && Object.keys(object1).every(index => object1[index] === object2[index]);
>
> const objectArraysAreEqual = (array1: Object[], array2: Object[]) =>
> array1.length === array2.length && array1.every((x, index) => objectsAreEqual(x, array2[index]));
Upvotes: 2
Views: 9356
Reputation: 11
You can use function like this
function deepEqual(obj1: object, obj2: object): boolean {
if (obj1 === obj2) {
return true;
}
if (typeof obj1 !== 'object' || obj1 === null ||
typeof obj2 !== 'object' || obj2 === null) {
return false;
}
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) {
return false;
}
for (const key of keys1) {
if (!obj2.hasOwnProperty(key)) {
return false;
}
if (!deepEqual(obj1[key], obj2[key])) {
return false;
}
}
return true;
}
Or using a lodash function follow this post https://bytesinsights.dev/blog/comparing-two-deep-objects-in-typescript-a-comprehensive-guide-with-examples
Upvotes: 1
Reputation: 4182
First, note that I cleaned up the data a bit. In your second example object, "isAllSelected": false,
appears twice which is not a valid javascript object. Also, the values array has the order of its elements swapped around which makes these actually not the same object, so for these demo examples I have them both as the exact same array.
Since you labeled this as a TypeScript question, I first made a TypeScript type for this object shape which I named "Foo".
type Foo = {
fieldId: string;
operationType: number;
definitionType: number;
values: string[];
isAllSelected: boolean,
dateRangeSelectionType: number
}
Then I defined the two objects as type Foo.
const fooA: Foo = {
"fieldId": "123456789",
"operationType": 1,
"definitionType": 1,
"values": ["123","456"],
"isAllSelected": false,
"dateRangeSelectionType": 0
}
const fooB: Foo = {
"isAllSelected": false,
"operationType": 1,
"definitionType": 1,
"fieldId": "123456789",
"values": ["123", "456"],
"dateRangeSelectionType": 0
}
Using the == and === operators are good for primitive types, but they will return "false" when comparing these objects, as will the "Object.is" function.
console.log(fooA == fooB) // false
console.log(fooA === fooB) // false
console.log(Object.is(fooA, fooB)) // false
So, looks like you will have to roll up your sleeves and go through checking every key and value in objects...
What you basically want to do is:
Make sure objects have the same keys.
Make sure those keys have the same values.
The tricky part is what happens if the values themselves are objects? In some cases you may want it to just be a shallow equals (eg. if you want your function to say they are equal even if the "values" array has different elements).
If you want the function to keep drilling down and check that EVERYTHING in the objects are the same then you want to check for "deep equality".
Here is one implementation of how you could implement this:
export default function deepEquals(object1: any, object2: any) {
const keys1 = Object.keys(object1);
const keys2 = Object.keys(object2);
if (keys1.length !== keys2.length) {
return false;
}
for (const key of keys1) {
const val1 = object1[key];
const val2 = object2[key];
const areObjects = isObject(val1) && isObject(val2);
if (
areObjects && !deepEquals(val1, val2) ||
!areObjects && val1 !== val2
) {
return false;
}
}
return true;
}
function isObject(object: Object) {
return object != null && typeof object === 'object';
}
Notice how this function returns true when comparing the objects:
import deepEquals from './deepEquals';
console.log(deepEquals(fooA, fooB)) // true
You could also use a library such as lodash that has deep object comparison:
import isEqual from 'lodash.isequal';
console.log(isEqual(fooA, fooB)) // true
Upvotes: 3