0

const array = [
  {
      "data": {
          "qty": "5",
          "toy": {
              "id": 3,
          },
          "available": "yes",
      }
  },
  {
      "data": {
          "qty": "5",
          "toy": {
              "id": 10,
          },
          "available": "no"
      }
  },
  {
      "data": {
          "qty": "59",
          "toy": {
              "id": 10,
          },
          "available": "yes",
      }
  },
  {
      "data": {
          "qty": "5",
          "toy": {
              "id": 3,
          },
          "available": "yes",
      }
  }
]


var result = [];
array.reduce(function(res, value) {
  if (!res['data']['toy'] || !res['data']['toy']['data']) {
    res['data'] = {...value['data'] };
    result.push(res['data'])
  }
  if (res['data']['available'] === value['data']['available'] && res['data']['toy']['id'] === value['data']['toy']['id']) {
    res['data']['qty'] = parseInt(res['data']['qty']) + parseInt(value['data'].qty)
  }
  return res;
}, {'data': {}});

console.log(result)

I am working on a js project and I need a bit of help here. From the array, How to get a new array that has qty as the sum of the other qty value which data.toy.id and available same. i.e. I want the below array. My code is not working as excepted. Changes to the same or new code are also fine. Thank you.

const array = [
  {
      "data": {
          "qty": "10",
          "toy": {
              "id": 3,
          },
          "available": "yes",
      }
  },
  {
      "data": {
          "qty": "5",
          "toy": {
              "id": 10,
          },
          "available": "no"
      }
  },
  {
      "data": {
          "qty": "59",
          "toy": {
              "id": 10,
          },
          "available": "yes",
      }
  }
]

  • Does this answer your question? [javascript reduce over multiple keys of objects in an array](https://stackoverflow.com/questions/51690140/javascript-reduce-over-multiple-keys-of-objects-in-an-array) – Rickard Elimää May 20 '22 at 07:19

4 Answers4

0

You group the array into an object, where the keys are concatenation of available and id properties and finally transform the object back to an array using Object.values.

const 
  array = [
    { data: { qty: "5", toy: { id: 3 }, available: "yes" } },
    { data: { qty: "5", toy: { id: 10 }, available: "no" } },
    { data: { qty: "59", toy: { id: 10 }, available: "yes" } },
    { data: { qty: "5", toy: { id: 3 }, available: "yes" } },
  ],
  result = Object.values(
    array.reduce((r, { data }) => {
      const k = data.available + data.toy.id;
      if (r[k]) {
        r[k].data.qty = String(Number(r[k].data.qty) + Number(data.qty));
      } else {
        r[k] = { data };
      }
      return r;
    }, {})
  );

console.log(result);
SSM
  • 2,855
  • 1
  • 3
  • 10
0

You can use Array#reduce() to create arrayHash object using as keys: ${c.data.toy.id}-${c.data.available}

Code:

const array = [{data: {qty: '5',toy: {id: 3,},available: 'yes',},},{data: {qty: '5',toy: {id: 10,},available: 'no',},},{data: {qty: '59',toy: {id: 10,},available: 'yes',},},{data: {qty: '5',toy: {id: 3,},available: 'yes',},},]

const arrayHash = array.reduce((a, { data }) => {
  const key = `${data.toy.id}-${data.available}`
  a[key] = a[key] || { data: { ...data, qty: 0 } }
  a[key].data.qty = (+a[key].data.qty + +data.qty).toString();
  return a
}, {})
const result = Object.values(arrayHash)

console.log(result)
Yosvel Quintero
  • 18,669
  • 5
  • 37
  • 46
  • 1
    Your solution does *not* add up the quantities of similar items. Replacing this `a[key].data.qty = c.data.qty` with `a[key].data.qty += c.data.qty` should make it work. – SSM May 20 '22 at 07:29
0

I'd suggest using Array.reduce() to group by a key, which will be combined value of the toy id and the available property.

We'd create a map of all toys based on this key, summing the quantity for each.

Finally, we'll use Object.values() to convert back into an array.

const array = [ { "data": { "qty": "5", "toy": { "id": 3, }, "available": "yes", } }, { "data": { "qty": "5", "toy": { "id": 10, }, "available": "no" } }, { "data": { "qty": "59", "toy": { "id": 10, }, "available": "yes", } }, { "data": { "qty": "5", "toy": { "id": 3, }, "available": "yes", } } ];

const result = Object.values(array.reduce((acc, { data: { qty, toy, available } }) => { 
    const key = `${toy.id}-${available}`;
    acc[key] = acc[key] || { data: { qty: 0, toy, available } };
    acc[key].data.qty += Number(qty);
    return acc;
}, {}))

console.log('Result:', result)
.as-console-wrapper { max-height: 100% !important; }
Terry Lennox
  • 29,471
  • 5
  • 28
  • 40
0

I'd use just reduce

const a1 = [
  {
      "data": {
          "qty": "5",
          "toy": {
              "id": 3,
          },
          "available": "yes",
      }
  },
  {
      "data": {
          "qty": "5",
          "toy": {
              "id": 10,
          },
          "available": "no"
      }
  },
  {
      "data": {
          "qty": "59",
          "toy": {
              "id": 10,
          },
          "available": "yes",
      }
  },
  {
      "data": {
          "qty": "5",
          "toy": {
              "id": 3,
          },
          "available": "yes",
      }
  }
]

const a2 = a1.reduce((acc, it) => {
  let found = acc.find(
    dp => dp.data.toy.id === it.data.toy.id && dp.data.available === it.data.available
  )
  if(found){
    found.data.qty = ( Number(found.data.qty) + Number(it.data.qty) ).toString()
  }
  else acc.push(it)
  return acc
}, [])

console.log(JSON.stringify(a2, null,2))
giulp
  • 2,200
  • 20
  • 26