Merge two objects(optimizing)

ItsMyLife :

I have n objects(with some nested structure). In the end, I'm expecting to get one merged object with all fields.

const result = {
  firstParam: {
    x: {
      id1: ["somedata1", "somedata2"],
      id3: ["somedata1", "somedata2"],
    },
    y: {
      id1: ["somedata1", "somedata2"],
      id3: ["somedata1", "somedata2"],
    },
    z: {
      id1: ["somedata1", "somedata2"],
      id3: ["somedata1", "somedata2"],
    }
  },
  secondParam: {
    x: {
      id1: ["somedata1", "somedata2"],
      id3: ["somedata1", "somedata2"],
    },
    y: {
      id1: ["somedata1", "somedata2"],
      id3: ["somedata1", "somedata2"],
    },
    z: {
      id1: ["somedata1", "somedata2"],
      id3: ["somedata1", "somedata2"],
    }
  },
  thirdParam: {
    x: {
      id1: ["somedata1", "somedata2"],
      id3: ["somedata1", "somedata2"],
    },
    y: {
      uuid1: ["somedata1", "somedata2"],
      id3: ["somedata1", "somedata2"],
    },
    z: {
      id1: ["somedata1", "somedata2"],
      id3: ["somedata1", "somedata2"],
    }
  }
}

const newObj1 = {
  firstParam: {
    x: {
      id2: ["somedata1", "somedata2"]
    },
    y: {
      id2: ["somedata1", "somedata2"]
    },
    z: {
      id2: ["somedata1", "somedata2"]
    }
  },
  secondParam: {
    x: {
      id2: ["somedata1", "somedata2"]
    },
    y: {
      id2: ["somedata1", "somedata2"]
    },
    z: {
      id2: ["somedata1", "somedata2"]
    }
  },
  thirdParam: {
    x: {
      id2: ["somedata1", "somedata2"]
    },
    y: {
      id2: ["somedata1", "somedata2"]
    },
    z: {
      id2: ["somedata1", "somedata2"]
    }
  }
}


const merge = (result, newObj) => {
  console.time("test merge")
  Object.keys(result).forEach(key => {
    result[key] = {
      x: {
        ...result[key].x,
        ...newObj[key].x
      },
      y: {
        ...result[key].y,
        ...newObj[key].y
      },
      z: {
        ...result[key].z,
        ...newObj[key].z
      }
    }
  })
  console.timeEnd("test merge")

  return result;
}

merge(result, newObj1);

This solution gives me an expected result(I'm getting an obj2, obj3 ... objn and every iteration I'm merging it to result), but when I'm getting more than 500 or 1000 newObj it works pretty slow. Is there any way to optimize it?

costadvl :

I assume you don't know the key naming of id1, id2, id3 ...

The performance issue is the spread operator, using a loop to get the key name and then executing only the needed substitution will make your code much faster.

import { Suite } from 'benchmark';

let suite = new Suite();


const result = {
    firstParam: {
        x: {
            id1: ["somedata1", "somedata2"],
            id3: ["somedata1", "somedata2"],
        },
        y: {
            id1: ["somedata1", "somedata2"],
            id3: ["somedata1", "somedata2"],
        },
        z: {
            id1: ["somedata1", "somedata2"],
            id3: ["somedata1", "somedata2"],
        }
    },
    secondParam: {
        x: {
            id1: ["somedata1", "somedata2"],
            id3: ["somedata1", "somedata2"],
        },
        y: {
            id1: ["somedata1", "somedata2"],
            id3: ["somedata1", "somedata2"],
        },
        z: {
            id1: ["somedata1", "somedata2"],
            id3: ["somedata1", "somedata2"],
        }
    },
    thirdParam: {
        x: {
            id1: ["somedata1", "somedata2"],
            id3: ["somedata1", "somedata2"],
        },
        y: {
            uuid1: ["somedata1", "somedata2"],
            id3: ["somedata1", "somedata2"],
        },
        z: {
            id1: ["somedata1", "somedata2"],
            id3: ["somedata1", "somedata2"],
        }
    }
}

const newObj1 = {
    firstParam: {
        x: {
            id2: ["somedata1", "somedata2"]
        },
        y: {
            id2: ["somedata1", "somedata2"]
        },
        z: {
            id2: ["somedata1", "somedata2"]
        }
    },
    secondParam: {
        x: {
            id2: ["somedata1", "somedata2"]
        },
        y: {
            id2: ["somedata1", "somedata2"]
        },
        z: {
            id2: ["somedata1", "somedata2"]
        }
    },
    thirdParam: {
        x: {
            id2: ["somedata1", "somedata2"]
        },
        y: {
            id2: ["somedata1", "somedata2"]
        },
        z: {
            id2: ["somedata1", "somedata2"]
        }
    }
}


const merge = (result: any, newObj: any) => {
    Object.keys(result).forEach(key => {
        result[key] = {
            x: {
                ...result[key].x,
                ...newObj[key].x
            },
            y: {
                ...result[key].y,
                ...newObj[key].y
            },
            z: {
                ...result[key].z,
                ...newObj[key].z
            }
        }
    })
    return result;
}

const mergeNoSpread = (result: any, newObj: any) => {
    Object.keys(result).forEach(key => {
        for (const key2 in newObj[key].x) {
            result[key].x[key2] = newObj[key].x[key2]
        }
        for (const key2 in newObj[key].y) {
            result[key].y[key2] = newObj[key].y[key2]
        }
        for (const key2 in newObj[key].z) {
            result[key].z[key2] = newObj[key].z[key2]
        }
    })

    return result;
}

suite
    .add('Spread usage', () => { merge(result, newObj1); })
    .add('No spread usage', () => { mergeNoSpread(result, newObj1); })
    .on('cycle', function (event: any) {
        console.log(String(event.target));
    })
    .on('complete', function () {
        console.log('Fastest is: ' + this.filter('fastest').map('name'));
    }).run({ 'async': true });


The performance results:

Spread usage x 794,766 ops/sec ±1.43% (87 runs sampled)
No spread usage x 2,176,879 ops/sec ±0.78% (88 runs sampled)
Fastest is: No spread usage

One iteration using console.time:

test merge: 0.252ms
test merge: 0.088ms

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=7296&siteId=1