yoyoma
yoyoma

Reputation: 3536

Use JS map/reduce to merge array of objects instead of forEach

I'm trying to learn better use of JS functions and I have a feeling what I'm after can be done using reduce or map or both, but I simply cannot find examples of this particular scenario:

I have an array of objects, eg:

const data =  [
    {
        "member": "111111",
        "offers": 0,
        "categories": 0,
        "total": 100,
        "favorites": 0
    },
    {
        "member": "111111",
        "offers": 2,
        "categories": 1,
        "total": 400,
        "favorites": 1
    },
    {
        "member": "222222",
        "offers": 1,
        "categories": 0,
        "total": 50,
        "favorites": 5
    }
]

The goal is to reduce to an array that merges all the key values into ONE array for each member, ie:

    {
        "member": "111111",
        "offers": 2,
        "categories": 1,
        "total": 500,
        "favorites": 1
    },
    {
        "member": "222222",
        "offers": 1,
        "categories": 0,
        "total": 50,
        "favorites": 5
    },

Therefore, there were two entries for member 111111, they have been merged and all the other values summed into a single array.

Honestly, everything I've tried is a mess, so apart from using the boring for loops or adding code here that is clearly rubbish, I hope you can point me in the right direction.

Upvotes: 3

Views: 1155

Answers (2)

FrankCamara
FrankCamara

Reputation: 348

Heres another example with just a reduce and indexOf

const data =  [
    {
        "member": "111111",
        "offers": 0,
        "categories": 0,
        "total": 100,
        "favorites": 0
    },
    {
        "member": "111111",
        "offers": 2,
        "categories": 1,
        "total": 400,
        "favorites": 1
    },
    {
        "member": "222222",
        "offers": 1,
        "categories": 0,
        "total": 50,
        "favorites": 5
    }
]

const merge = (target, props) => {
  for(p in props){
    if(p !== 'member') {
      target[p] += props[p]
    }
  }
  return target
}

const a = data.reduce((res, d) => {
  const idx = res.findIndex(r => r.member === d.member)
  if (idx >= 0) {
    const newRes = merge(res[idx], {...d})
    res.splice(res[idx], 1, newRes)
  } else {
    res.push(d)
  }
  return res
}, [])

console.log(a)

Upvotes: 2

marvel308
marvel308

Reputation: 10458

You can do

const data =  [
    {
        "member": "111111",
        "offers": 0,
        "categories": 0,
        "total": 100,
        "favorites": 0
    },
    {
        "member": "111111",
        "offers": 2,
        "categories": 1,
        "total": 400,
        "favorites": 1
    },
    {
        "member": "222222",
        "offers": 1,
        "categories": 0,
        "total": 50,
        "favorites": 5
    }
]


let result = data.reduce((a, b) => {
  a[b.member] = a[b.member] || {member : b.member};
  for(let property of Object.keys(b)){
    if(property == 'member') continue;
    a[b.member][property] = a[b.member][property] || 0;
    a[b.member][property] += b[property];
  }
  return a;
}, {});

result = Object.keys(result).map(e => result[e]);

console.log(result);

Upvotes: 4

Related Questions