Skip to content

How to merge two object arrays by adding matching object in as a new field

I have these two arrays:

const goodCars = [
    { name: 'ferrari', price: 22000, condition: { isGood: true, isBad: false } },
    { name: 'ford', price: 21000, condition: { isGood: true, isBad: false } },
    { name: 'bmw', price: 20000, condition: { isGood: true, isBad: false } },
  ];

  const badCars = [
    { name: 'ford', price: 1111, condition: { isGood: false, isBad: true } },
    { name: 'honda', price: 8000, condition: { isGood: false, isBad: true } },
  ];

My goal is to produce this final array:

  const finalCarList = [
    { name: 'ferrari', price: 22000, condition: { isGood: true, isBad: false } },
    {
      name: 'ford',
      price: 21000,
      condition: { isGood: true, isBad: false },
      toCompareWith: { name: 'ford', price: 1111, condition: { isGood: false, isBad: true } },
    },
    { name: 'bmw', price: 20000, condition: { isGood: true, isBad: false } },
    { name: 'honda', price: 8000, condition: { isGood: false, isBad: true } },
  ];

Basically I want to merge the two goodCars and badCars arrays into one but if the cars exists in both good and badd arrays then I want to add the bad car to the good car array as a new field toCompareWith: {...} (seen above)

I’ve tried using map(), reduce(), for loops, etc. but my brain has hit a wall and I’m not getting any closer.

My attempt:

 goodCars.map((gc) => {
    badCars.map((bc) => {
      if (isCarMatch(gc, bc)) {
        finalCarList = [
          ...finalCarList,
          { ...gc, toCompareWith: bc },
        ];
      }
    });
 });

Answer I went with based on the below marked correct one: ✅

  let finalCarList: Array<Car> = [...goodCars];

  badCars?.forEach((bc) => {
    const match: Car | undefined = goodCars.find((gc) => isCarMatch(gc, bc));
    match
      ? (match.toCompareWith = bc) // Slot in matching item
      : (finalCarList = [...finalCarList, bc]);
  });

Answer

You shouldn’t use nested loops.

Start by copying goodCars to finalCarList. Then loop over badCars. If the car is in goodCars, add the bad car as the toCompareWith property. Otherwise, push it into finalCarList.

finalCarList = [...goodCars];
badCars.forEach(bc => {
    match = goodCars.find(gc => isCarMatch(gc, bc));
    if (match) {
        match.toCompareWith = bc;
    } else {
        finalCarList.push(bc);
    }
});

Also, in general you shouldn’t use map() if the callback function doesn’t return anything. If it’s called only for side effects, use forEach().