I have two arrays of objects
const a = [ { name: 'apple', type: 'fruit' }, { name: 'berry', type: 'fruit' }, { name: 'grape', type: 'fruit' }, { name: 'broccoli', type: 'vegetable' }, { name: 'cabbage', type: 'vegetable' }, ] const b = [ { name: 'apple', amount: 4 }, { name: 'berry', amount: 5 }, { name: 'grape', amount: 3 }, { name: 'broccoli', amount: 7 }, { name: 'avocado', amount: 8 }, ]
I need to write a function to output an array with objects with the same name being merged into one.
const c = [ { name: 'apple', type: 'fruit', amount: 4 }, { name: 'berry', type: 'fruit', amount: 5 }, { name: 'grape', type: 'fruit', amount: 3 }, { name: 'broccoli', type: 'vegetable', amount: 7 }, { name: 'cabbage', type: 'vegetable', amount: 0 }, { name: 'avocado', type: undefined, amount: 8 }, ]
As you can see here, objects that share the same name are merged into one object with a few exceptions:
- if
type
field is missing, we would need to add it and make itundefined
- if
amount
field is missing, we need to add it and make it0
Here is my attempt:
function fillMissingFields(object) { console.log('object', object) let newObject = { ...object } if (object.type === undefined) { newObject = { ...object, type: undefined } } if (object.amount === undefined) { newObject = { ...newObject, amount: 0 } } return newObject } function join(a, b) { const results = [] for (const aItem of a) { const bItems = b.filter((item) => item.name === aItem.name) let newObject if (bItems.length) { for (const bItem of bItems) { newObject = { ...newObject, ...bItem } } newObject = fillMissingFields({ ...newObject, ...aItem }) } else { newObject = fillMissingFields(aItem) } results.push(newObject) } return results }
Besides the fact that it has a really bad time complexity O(n^2)
. It actually has a bug where if an object only appears in b
array, that object will be omitted entirely from the new array.
Can anyone try to help me come up with a more robust and efficient algorithm to tackle this problem?
Advertisement
Answer
Make a collection whose keys are the name
s, whose values are the combined objects, which starts out with an undefined type
and an amount of 0. Iterate through both arrays, assigning the property values as needed, then at the end, take the collection’s values:
const a = [ { name: 'apple', type: 'fruit' }, { name: 'berry', type: 'fruit' }, { name: 'grape', type: 'fruit' }, { name: 'broccoli', type: 'vegetable' }, { name: 'cabbage', type: 'vegetable' }, ]; const b = [ { name: 'apple', amount: 4 }, { name: 'berry', amount: 5 }, { name: 'grape', amount: 3 }, { name: 'broccoli', amount: 7 }, { name: 'avocado', amount: 8 }, ]; const objsByName = new Map(); const getObj = (name) => { if (!objsByName.has(name)) { objsByName.set(name, { name, type: undefined, amount: 0 }); } return objsByName.get(name); }; for (const { name, type } of a) { getObj(name).type = type; } for (const { name, amount } of b) { getObj(name).amount = amount; } console.log([...objsByName.values()]);