3

I have two nested objects obj1 and obj2 and I want to compare them and the recursively return an object that for each nested key has a equality-like boolean flag

So for a given obj1 like

var obj1 = {
    prop1: "BAR",
    prop2: "foo",
    prop3: [
        {
            id: 1,
            prop4: "foo",
            prop5: "a"
        },
        {
            id: 2,
            prop4: "foo",
            prop5: "b"
        },
        {
            id: 3,
            prop4: "foo",
            prop5: "e"
        }
    ]
}

And the obj2 like

var obj2 = {
    prop1: "FOO",
    prop2: "foo",
    prop3: [
        {
            id: 1,
            prop4: "bar",
            prop5: "b"
        },
        {
            id: 2,
            prop4: "foo",
            prop5: "a"
        },
        {
            id: 4,
            prop4: "foo",
            prop5: "e"
        }
    ],
    prop6: "new"
}

It should return

var equality = {
    prop1: false,
    prop2: true,
    prop3: [
        {
            id: 1,
            prop4: false,
            prop5: false
        },
        {
            id: 2,
            prop4: true,
            prop5: false
        },
        {
            id: 3,
            prop4: null,
            prop5: null
        },
        {
            id: 4,
            prop4: true,
            prop5: true
        }
    ],
    prop6: true
}

I have to compare two objects and return true for same values. And for inside the array I have to compare with ID(key) and check if prop4, prop 5 have changed and return false if changed. For Data in obj 1 and not present in obj 2 => we can neglector show as null as shown in result(equality) For Data in obj 2 and not present in obj 1 => should be flagged as true for all props in it.

The solution given by Nina Scholz in Compare nested objects in JavaScript and return keys equality has helped me but only problem I am facing is for prop3 I am getting as nested fields but I need it as same formatting as the array.

It would be very much helpful for me if any one get the right solution. I am new to JavaScript and learning it would help me a lot.

Nur
  • 2,361
  • 2
  • 16
  • 34
  • why `equality.prop1` is `true`? because `obj1.prop1` isn't equal to `obj2.prop1`, shouldn't it be `false` ? – Nur Apr 22 '21 at 04:10
  • Yes it should be false. I will edit the question. Thank you for pointing out. – arun kumar v Apr 22 '21 at 14:15
  • And why you keep `number` ? – Nur Apr 22 '21 at 16:40
  • I want them to be compared with number not by index so I needed it. So as shown in my result the number will be present. I think this works and if you could do this scenario and " For Data in obj 1 and not present in obj 2 => we can neglect For Data in obj 2 and not present in obj 1 => should be flagged as true for all props in it." this that wouold be very helpful for me. Thank you very much again. – arun kumar v Apr 22 '21 at 16:41
  • It helped me, need to check for number and other condition as I said I need to compare them with number and see if in that array for that particular "number", the props have changed are not. – arun kumar v Apr 22 '21 at 17:02
  • add this line `if (key == "number" && key in x && key in y && x[key] == y[key]) { temp[key] = x[key]; continue; }` in 3rd `if..for..of` loop, To Keep `number` – Nur Apr 22 '21 at 17:03
  • Thank you very much it helped me. Just need to convert to es6 and good to go. I appreciate that. – arun kumar v Apr 22 '21 at 17:06
  • I checked it and it is working fine. Only one problem is if there is difference in length of the arrays I am getting it result as number = false for some indexes. Just looking into it – arun kumar v Apr 22 '21 at 17:26
  • So when you want to keep `number` exactly ? – Nur Apr 22 '21 at 17:37
  • Okay I got it. So I am checking always with number and " if Data in obj 1 is not present in obj 2 => we can neglect example obj1 - prop3[2]- number 3 ; if Data is present obj 2 and not present in obj 1 => should be flagged as true for all props in it. obj2 - prop3[2]-number 4. I edited the question and sorry for the confusion. I am new to this and learning it. – arun kumar v Apr 22 '21 at 17:47
  • Number should always be present as equality = { prop1: false, prop2: true, prop3: [ { number: 1, prop4: false, prop5: false }, { number: 2, prop4: true, prop5: false }, { number: 4, prop4: true, prop5: true } ], prop6: true } – arun kumar v Apr 22 '21 at 17:47
  • 1
    Ok! We are checking , If `key` is `'number'`, And both object should have it , And `number` in both object should equal... Got it ? – Nur Apr 22 '21 at 17:52
  • Instead of comparing with array index, the comparision point here would be the number, I have to compare with number in both arrays and return true or false for the props inside that that paricular index of number? Is it clear now, or did I confuse you more. To be clear, I have to compare number 1 items with number 1 items in obj 1 and 2 and see if prop 4 and prop5 are same or different. For special case like number 3 (deleted in obj 2) in obj 1 i can neglect it as it is not present in obj 2, but for number 4 (added in obj 2) in obj 2 which is not present in obj 1, I have to show as true – arun kumar v Apr 22 '21 at 18:07
  • All time, I have hard time understanding every questions on stack overflow. Unless There is an example . So can I have an example? – Nur Apr 22 '21 at 18:27
  • Sorry to confuse you. I understand your concern. I have updated the question codes please check obj1 obj 2 and equality, We are almost there and might need some tweaking. Just need to compare prop3 in each obj with id's always. please see the edited question now. If a particular list item is not available in the second array, it should return null. I am able to make it clear now? – arun kumar v Apr 22 '21 at 18:36
  • Please let me if I had been able to make it clear or is it confusing and need to explain it better from myside. – arun kumar v Apr 22 '21 at 18:51
  • Trying to do better explanation, just need to compare two arrays with ID number(id=1 in obj1 compare to id=1 in obj2) in each array and display true/false for (prop4, prop5) equal/unequal values. If a item(id =3 in obj 1) in list is present in obj1 and not present in obj 2 we can ignore it and don't display anything in result or we can display that in result as {id: 3, prop4: null, prop5: null} and if an ID list item is present in obj 2 (ID 4) and not in obj 1 just display in result as true for its siblings {id:4, prop4: true, prop5: true}. – arun kumar v Apr 22 '21 at 19:20
  • Refactored code a bit. And [your solution](https://gist.github.com/nurmohammed840/667c0839e4adbd476457da6327dfce2b) – Nur Apr 23 '21 at 08:38

1 Answers1

3

Some tricky recursion can do the job.

var obj1 = { prop1: 1, prop2: "foo", prop3: [{ number: 1, prop4: "foo", prop5: "a" }, { number: 2, prop4: "foo", prop5: "b" }] }
var obj2 = { prop1: 3, prop2: "foo", prop3: [{ number: 1, prop4: "bar", prop5: "b" }, { number: 2, prop4: "foo", prop5: "a" }, { number: 3, prop4: "foo", prop5: "e" }], prop6: "new" }

const isObject = v => v !== null && typeof v == "object";

function getDifference(x, y = x) {
    if (x === undefined) x = y;
    if (Array.isArray(x) && Array.isArray(y)) {
        const temp = [];
        for (let i = 0; i < (x.length + y.length) / 2; i++)
            temp.push(getDifference(x[i], y[i]))

        return temp;
    }
    if (isObject(x) && isObject(y)) {
        const temp = {};
        for (const key of new Set([...Object.keys(x), ...Object.keys(y)]))
            temp[key] = getDifference(x[key], y[key])

        return temp;
    }
    return x === y;
}

console.log(getDifference(obj1, obj2));
Nur
  • 2,361
  • 2
  • 16
  • 34