skip to Main Content

I have two arrays of objects of the same structure.
Array 1 contains elements such as:

[
        {
            id: "1",
            name: "XX",
            displayName: "XX",
            count: 12
        },
        {
            id: "2",
            name: "XX",
            displayName: "XX",
            count: 12
        },
        {
            id: "3",
            name: "XX",
            displayName: "XX",
            count: 12
        }
    ]

Array 2 contains elements such as:

[
        {
            id: "1",
            count: 2
        },
        {
            id: "3",
            count: 5
        }
    ]

I need a resulting array of this type:

[
        {
            id: "1",
            name: "XX",
            displayName: "XX",
            count: 10
        },
        {
            id: "2",
            name: "XX",
            displayName: "XX",
            count: 12
        },
        {
            id: "3",
            name: "XX",
            displayName: "XX",
            count: 7
        }
    ]

That means I need a new array containing all items from array1 with that same structure, but if in array 2 i have a matching ID the new count should be the difference between the value of the two, otherwise it is unchanged.
I have been trying to implement this using .reduce() but I am having some trouble getting the logic together, can anyone shed some light on how should I think this through? I am fairly new to JS and I come from a mostly C99 and Python background.

I am excluding the use of nested for loops for this for obvious reasons.
A solution I had in mind was to make all the "count" values in in the second array negative, and using this other method I found on this same website. This solution also implies all attributes are int values and sums them all up:

        const sumItem = ({ id, ...a }, b) => ({
            id,
            ...Object.keys(a)
                .reduce((r, k) => ({ ...r, [k]: a[k] + b[k] }), {})
            });
        

        const sumObjectsByKey = (...arrs) => [...
            [].concat(...arrs) // combine the arrays
                .reduce((m, o) => // retuce the combined arrays to a Map
                    m.set(o.id, // if add the item to the Map
                        m.has(o.id) ? subItem(m.get(o.id), o) : { ...o } // if the item exists in Map, sum the current item with the one in the Map. If not, add a clone of the current item to the Map
                    )
                    , new Map).values()]

But that does not feel elegant or "right", and I feel like I should instead focus on understanding methods related to maps a bit better. Can anybody help?

2

Answers


  1. One method is to use Array#map to create the array with updated counts and Array#find to get the matching element by id from the second array (if any) on each iteration.

    let arr1=[{id:"1",name:"XX",displayName:"XX",count:12},{id:"2",name:"XX",displayName:"XX",count:12},{id:"3",name:"XX",displayName:"XX",count:12}],
        arr2=[{id:"1",count:2},{id:"3",count:5}];
    let res = arr1.map(o => ({...o, count : o.count - 
      (arr2.find(x => o.id === x.id)?.count ?? 0)}));
    console.log(res);

    A more efficient method would be to first create an object that maps each id in the second array to its count, then use those counts when generating the new array.

    let arr1=[{id:"1",name:"XX",displayName:"XX",count:12},{id:"2",name:"XX",displayName:"XX",count:12},{id:"3",name:"XX",displayName:"XX",count:12}],
        arr2=[{id:"1",count:2},{id:"3",count:5}];
    let counts2 = arr2.reduce((acc, curr) => {
      acc[curr.id] = curr.count;
      return acc;
    }, {});
    let res = arr1.map(o => ({...o, count : o.count - (counts2[o.id] ?? 0)}));
    console.log(res);
    Login or Signup to reply.
  2. Reduce to an intermediate object and take the values of that:

    const array1 = [{
      id: "1",
      name: "XX",
      displayName: "XX",
      count: 12
    }, {
      id: "2",
      name: "XX",
      displayName: "XX",
      count: 12
    }, {
      id: "3",
      name: "XX",
      displayName: "XX",
      count: 12
    }];
    
    const array2 = [{
      id: "1",
      count: 2
    }, {
      id: "3",
      count: 5
    }];
    
    const result = Object.values([...array1, ...array2].reduce((a, v) => {
      if (a[v.id]) a[v.id].count -= v.count
      else a[v.id] = { ...v }
      return a;
    }, {}));
    
    console.log(result);
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search