Search code examples
javascriptobjectnestedduplicatesreduce

reducing nested object key value inside an an array


i have the following arrays

array1 = [
    {a:{key:1 , value: 10} , b:{key:1 , value:12} , c:{key:1 , value: 5} , d:{key:1 , value:2}},
    {a:{key:2 , value: 10} , b:{key:2 , value:12} , c:{key:2 , value: 5} , d:{key:2 , value:2}},
    {a:{key:3 , value: 10} , b:{key:3 , value:12} , c:{key:3 , value: 5} , d:{key:3 , value:2}},
]
array2 = [
    {a:{key:1 , value: 10} , b:{key:1 , value:12} , c:{key:1 , value: 5} , d:{key:1 , value:2}},
    {a:{key:2 , value: 10} , b:{key:2 , value:12} , c:{key:2 , value: 5} , d:{key:2 , value:2}},
    {a:{key:4 , value: 10} , b:{key:4 , value:12} , c:{key:4 , value: 5} , d:{key:4 , value:2}},
]

reduced array based on key should look like this:

combinedArray= [
    {a:{key:1 , value: 20} , b:{key:1 , value:24} , c:{key:1 , value: 10} , d:{key:1 , value:4}},
    {a:{key:2 , value: 20} , b:{key:2 , value:24} , c:{key:2 , value: 10} , d:{key:2 , value:4}},
    {a:{key:3 , value: 10} , b:{key:3 , value:12} , c:{key:3 , value: 5} , d:{key:3 , value:2}},
    {a:{key:4 , value: 10} , b:{key:4 , value:12} , c:{key:4 , value: 5} , d:{key:4 , value:2}},
]

first i tried to merge the two arrays using const mergedArray = [...array1, ...array2]

now i want to check for key duplicates. for example, if there is key1 in both array1 and array2, remove the duplicates then combine the values of that key.

this is what i have tried but it is only iterating through a.key only:

function kdeAdder(param) {
    const array = [param.a]
    let tempHistory = [];
    for(let x=0;x<array.length;x++){
        array[x].forEach((item)=>{
            let noMatch = true; 
            if(tempHistory.length > 0) {
                tempHistory.forEach((tempItem, i)=>{
                    if(item.key === tempItem.key) {
                        tempHistory[i].value += item.value;
                        noMatch = !noMatch; 
                    }
                });
            }
            return (noMatch) ? tempHistory.push(item) : null;
        });

    }
    return tempHistory;
}
kdeAdder(mergedArray);


Solution

  • As you confirmed the key inner property is commonly shared by the four "a", "b", "c", "d" objects in an outer object, the a.key value can be used to identify which outer objects should merge.

    You could group all objects (irrespective of whether they occur in array1 or array2) by that a.key, and then aggregate objects that occur in the same group. Both of these actions can be accomplished with a reduce call:

    const aggregate = (objects) =>
        objects.reduce((x, y) => ({
            a: { key: x.a.key, value: x.a.value + y.a.value },
            b: { key: x.b.key, value: x.b.value + y.b.value },
            c: { key: x.c.key, value: x.c.value + y.c.value },
            d: { key: x.d.key, value: x.d.value + y.d.value },
        }));
                                    
    const merge = (array1, array2) =>
        Object.values(array1.concat(array2).reduce((acc, obj) => {
            (acc[obj.a.key] ??= []).push(obj);
            return acc;
        }, {})).map(aggregate);
        
    const array1 = [
        {a:{key:1 , value: 10} , b:{key:1 , value:12} , c:{key:1 , value: 5} , d:{key:1 , value:2}},
        {a:{key:2 , value: 10} , b:{key:2 , value:12} , c:{key:2 , value: 5} , d:{key:2 , value:2}},
        {a:{key:3 , value: 10} , b:{key:3 , value:12} , c:{key:3 , value: 5} , d:{key:3 , value:2}},
    ];
    
    const array2 = [
        {a:{key:1 , value: 10} , b:{key:1 , value:12} , c:{key:1 , value: 5} , d:{key:1 , value:2}},
        {a:{key:2 , value: 10} , b:{key:2 , value:12} , c:{key:2 , value: 5} , d:{key:2 , value:2}},
        {a:{key:4 , value: 10} , b:{key:4 , value:12} , c:{key:4 , value: 5} , d:{key:4 , value:2}},
    ]
    
    console.log(merge(array1, array2));