Cemal Okten
Cemal Okten

Reputation: 828

Apply the keys of one object onto another with different values but identical structure

Given the two following objects:

const obj1 = {
   value1: 'Hello',
   value2: 'Goodbye',
   value3: ['yes', 'no'],
   value4: {
      value5: 'Phone'
   }
}

const obj2 = {
   v1: 'Orange',
   v2: 'Apple',
   v3: ['Cat', 'Dog'],
   v4: {
      v5: 'Basketball'
   }
}

How can I apply the keys of the first object onto the second object, assuming the structure/number of key/values is identical? Returning this:

{
   value1: 'Orange',
   value2: 'Apple',
   value3: ['Cat', 'Dog'],
   value4: {
      value5: 'Basketball'
   }
}

Any help would be appreciated!

Upvotes: 0

Views: 60

Answers (3)

Scott Sauyet
Scott Sauyet

Reputation: 50797

I would suggest you might really want to rethink this. We can write such a function. Andrew Parks' accepted answer is one way. Here's another:

const copyStruct = (x, y, xs = Object .entries (x), ys = Object .values (y)) => 
  Object .assign (
    Array .isArray (x) ? [] : {}, 
    ... xs .map (([k, v], i) => ({[k]: Object (v) === v ? copyStruct (v, ys[i]) : ys[i]}))
  )

const obj1 = {"value1":"Hello","value2":"Goodbye","value3":["yes","no"],"value4":{"value5":"Phone"}}
const obj2 = {"v1":"Orange","v2":"Apple","v3":["Cat","Dog"],"v4":{"v5":"Basketball"}}

console .log (copyStruct (obj1, obj2))

But, this is extremely fragile. The best way to think of Objects is as unordered collections of key-value pairs. Here you're depending upon ordering in a very tenuous manner.

For example, this really should be a no-op:

const temp = obj1 .value1
delete obj1 .value1
obj1 .value1 = temp

obj1 has the same values for the same keys as it did when it was defined. But now if you run it through either Andrew's code or mine, your result will look like this:

{
  value2: "Orange",
  value3: ["A", "p"],
  value4: {value5: "Cat"},
  value1: {v5: "Basketball"}
}

Or for another example, without our even modifying the object, our iteration order is different when the keys look like small integers:

const obj1 = {"3": "Hello",     "1":"Goodbye", "2":"Phone",      "4": "yes"}
const obj2 = {"5": "Orange",    "6":"Apple",   "4":"Basketball", "7": "cat"}

will result in:

             {"1":"Basketball", "2":"Orange",  "3":"Apple",      "4":"cat"}

There is a possible recovery from all this mess. I'm sure your example is just dummy sample data, but if you actually have a direct relationship between the keys in the two objects, such as

const newKey = key .replace ('value', 'v')

then we could write a pretty simple recursive function to solve your problem. Otherwise, I would suggest reconsidering your approach.

Upvotes: 0

Pal Singh
Pal Singh

Reputation: 1974

From your problem statement, it seems like you want to modify keys of the obj2 and there is no need for obj1.

You can achieve that in a simple way using recursion:

function updateKeys(obj) {
   for (let key in obj) {
     const newKey = `value${key.slice(1)}`
     obj[newKey] = obj[key]
     delete obj[key]
     
     if (typeof obj[newKey] === 'object' && !Array.isArray(obj[newKey])) {
       updateKeys(obj[newKey])
     }
   }
}
updateKeys(obj2)

Upvotes: 0

Andrew Parks
Andrew Parks

Reputation: 8087

const obj1 = {"value1":"Hello","value2":"Goodbye","value3":["yes","no"],"value4":{"value5":"Phone"}}
const obj2 = {"v1":"Orange","v2":"Apple","v3":["Cat","Dog"],"v4":{"v5":"Basketball"}}

const values = (a,b,c) => (c = Object.values(b), Object.entries(a).map(([k,v],i)=>[k,v,c[i]]))
const f = (a,b) => (values(a,b).forEach(([k,v,v2])=>v instanceof Object ? f(v,v2) : a[k]=v2), a)
console.log(f(structuredClone(obj1), obj2))

Upvotes: 2

Related Questions