4

I would like to compare two objects and want to make one new object which have common proprty of it. I have seen lot of solutions to take difference but not sure how we can take common values.

Here is my objects where if obj1 have iscommisionAccount false and obj2 have iscommisonAccount true then my result should not have value as it is not matched if both have same property then only will get result.

I know we can use filter if we have arrays of objects but what if we have only objects.

obj 1 = {
   "val1":"test",
   "stream":{
      "iscommisonAccount":false,
      "istradeAccount":true
   }
}

 obj 2 = {
   "val1":"test",
   "stream":{
      "iscommisonAccount":true,
      "istradeAccount":true
   }
}

result = {
   "stream":{
      "istradeAccount":true
   }
}

diffrent examples:

obj 1 = {
   "val1":"test",
   "stream":{
      "iscommisonAccount":false,
      "istradeAccount":true
   }
}

 obj 2 = {
   "val1":"test",
   "stream":{
      "iscommisonAccount":true,
      "istradeAccount":false
   }
}

result = {
   "stream":{
   }
}

or

obj 1 = {
   "val1":"test",
   "stream":{
      "iscommisonAccount":true,
      "istradeAccount":true
   }
}

 obj 2 = {
   "val1":"test",
   "stream":{
      "iscommisonAccount":true,
      "istradeAccount":true
   }
}

result = {
   "stream":{
      "iscommisonAccount":true,
      "istradeAccount":true
   }
}

2
  • 1
    I found solution form here enter link description here Commented Dec 8, 2020 at 21:37
  • it seems getting difference then the common values. Commented Dec 8, 2020 at 21:41

2 Answers 2

5

Something like this should work. A recursive function that just runs through all the keys of the object.

It doesn't handle arrays, but it can be modified to if that's a requirement.

function findCommonValues(obj1, obj2) {
    var result = {}
    for (let key in obj1) {
        if (obj1[key] && obj1[key] === obj2[key]) result[key] = obj1[key]
        else if (typeof obj1[key] === 'object' && obj1[key] !== null) {
            result[key] = findCommonValues(obj1[key], obj2[key])
        }
    }
    return result;
}

const obj1 = {
    "val1": "test",
    "stream": {
        "iscommisonAccount": false,
        "istradeAccount": true
    }
}

const obj2 = {
    "val1": "test",
    "stream": {
        "iscommisonAccount": true,
        "istradeAccount": true
    }
}

const obj3 = {
    "val1": "test",
    "stream": {
        "iscommisonAccount": false,
        "istradeAccount": true
    }
}

const obj4 = {
    "val1": "test",
    "stream": {
        "iscommisonAccount": true,
        "istradeAccount": false
    }
}

const obj5 = {
    "val1":"test",
    "stream":{
       "iscommisonAccount":true,
       "istradeAccount":true
    }
 }
 
 const obj6 = {
    "val1":"test",
    "stream":{
       "iscommisonAccount":true,
       "istradeAccount":true
    }
 }

console.log(findCommonValues(obj1, obj2))
console.log(findCommonValues(obj3, obj4))
console.log(findCommonValues(obj5, obj6))

If you want it as small as possible. This is really the best I can do.

const commonValues = (obj1, obj2) => Object.keys(obj1).reduce((result, key) => obj1[key] && obj1[key] === obj2[key] ? { ...result, [key]: obj1[key] } : typeof obj1[key] === 'object' && obj1[key] !== null ? { ...result, [key]: commonValues(obj1[key], obj2[key]) } : result, {});

const obj1 = {
    "val1": "test",
    "stream": {
        "iscommisonAccount": false,
        "istradeAccount": true
    }
}

const obj2 = {
    "val1": "test",
    "stream": {
        "iscommisonAccount": true,
        "istradeAccount": true
    }
}

const obj3 = {
    "val1": "test",
    "stream": {
        "iscommisonAccount": false,
        "istradeAccount": true
    }
}

const obj4 = {
    "val1": "test",
    "stream": {
        "iscommisonAccount": true,
        "istradeAccount": false
    }
}

const obj5 = {
    "val1": "test",
    "stream": {
        "iscommisonAccount": true,
        "istradeAccount": true
    }
}

const obj6 = {
    "val1": "test",
    "stream": {
        "iscommisonAccount": true,
        "istradeAccount": true
    }
}

console.log(commonValues(obj1, obj2))
console.log(commonValues(obj3, obj4))
console.log(commonValues(obj5, obj6))

TypeScript Version

export type KeyValueObject = {
    [key: string]: number | boolean | string | KeyValueObject
}

export const isKeyValueObject = (obj1: number | boolean | string | KeyValueObject): obj1 is KeyValueObject => typeof obj1 === 'object' && obj1 !== null;

export const commonValues = (obj1: KeyValueObject, obj2: KeyValueObject): KeyValueObject =>
    Object.keys(obj1).reduce((result, key) =>
        obj1[key] && obj1[key] === obj2[key]
            ? { ...result, [key]: obj1[key] }
            : isKeyValueObject(obj1[key]) && isKeyValueObject(obj2[key])
                ? { ...result, [key]: commonValues(obj1[key] as KeyValueObject, obj2[key] as KeyValueObject) }
                : result,
        {}
    );
Sign up to request clarification or add additional context in comments.

7 Comments

thanks a lot.. it helps.. just as curiosity.. do we use any third party library like lodash or is there any typescript solution available to shorter the code?
I only see an intersect function for arrays, not objects in lodash.
I added another function that's about as compact as I can get it. It's one line but a long one line lol.
It is throwing some type error like this...Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
You must be using TypeScript, I added a version for TypeScript that should work.
|
4

Here is a simple example that uses a combination of Object.values and Object.keys as arrays that are filtered to produce your prescribed output:

let obj1 = { "val1":"test", "stream":{ "iscommisonAccount":false, "istradeAccount":true } }; 
let obj2 = { "val1":"test", "stream":{ "iscommisonAccount":true, "istradeAccount":true } };


let obj3 = { "val1":"test", "stream":{ "iscommisonAccount":true, "istradeAccount":true } }; 
let obj4 = { "val1":"test", "stream":{ "iscommisonAccount":false, "istradeAccount":true } };

let obj5 = { "val1":"test", "stream":{ "iscommisonAccount":false, "istradeAccount":false } }; 
let obj6 = { "val1":"test", "stream":{ "iscommisonAccount":false, "istradeAccount":false } };

let obj7 = { "val1":"test", "stream":{ "iscommisonAccount":true, "istradeAccount":false } }; 
let obj8 = { "val1":"test", "stream":{ "iscommisonAccount":true, "istradeAccount":false } };

interface Data {stream:{[key: string]: boolean}};

function objFilter(objA: Data, objB: Data): Data {
  let out: Data = {stream:{}};
  Object.keys(objA.stream).filter((value, idx) =>
    Object.values(objA.stream)[idx] === Object.values(objB.stream)[idx] ? 
      out.stream[value] = Object.values(objA.stream)[idx] :
      false
  );
  return out;
}
console.log(objFilter(obj1, obj2)); //istradeAccount
console.log(objFilter(obj3, obj4)); //istradeAccount
console.log(objFilter(obj5, obj6)); //iscommisonAccount && istradeAccount
console.log(objFilter(obj7, obj8)); //iscommisonAccount && istradeAccount
console.log(objFilter(obj2, obj7)); //iscommisonAccount

9 Comments

it is failing if I do opposite, For example.. obj1 = { "val1":"test", "stream":{ "iscommisonAccount":true, "istradeAccount":true } } obj2 = { "val1":"test", "stream":{ "iscommisonAccount":false, "istradeAccount":true } } Result is coming: { "stream": { "iscommisonAccount": true, "istradeAccount": true } }
Yes, sorry, I naively was checking "backwards". The solution is now correct and shows various inputs.
Thanks a lot.. Just last question.. How I can cast this function properly.. because I get this 2 errors .. 1. at the out.stream[value] : (property) stream: {} Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'. No index signature with a parameter of type 'string' was found on type '{}'.
2nd error: at function : (parameter) objA: any Parameter 'objA' implicitly has an 'any' type.
3rd error : expected call-signature: 'objFilter' to have a typedef (typedef)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.