Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

ES6 reduce array of objects with conditions

I’m stucked in a (in my opinion) complex reduce method.

Given is an array of objects.

const data = 
[
  {
    "key" : "test1",
    "value" : 32,
    "type"  : "OUT"
  },
  {
    "key" : "test1",
    "value" : 16,
    "type"  : "OUT"
  },
  {
    "key" : "test1",
    "value" : 8,
    "type"  : "IN"
  },
  {
    "key" : "test2",
    "value" : 32,
    "type"  : "OUT"
  },
  {
    "key" : "test2",
    "value" : 16,
    "type"  : "IN"
  },
  {
    "key" : "test2",
    "value" : 8,
    "type"  : "OUT"
  },  
];

I want to get the sum of values of each object grouped by key attribute. There are two type attributes (IN, OUT) where OUT should be interpreted as negative value.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

So in the example above, I’m expecting following result object:

 //-32 - 16 + 8 = -40
 {
    "key" : "test1",
    "value" : -40,
    "type"  : "-"
  },
 //-32 + 16 - 8 = -24
 {
    "key" : "test2",
    "value" : -24,
    "type"  : "-"
  },

I’m grouping the data using the groupBy function of this SO answer.

Now I’m trying to get the sum using reduce with a filter, like in this SO answer.

However, it delivers me the wrong sums (16 and 8) + since I use filter – only one type is considered.


Here is my code:

const data = 
[
  {
    "key" : "test1",
    "value" : 32,
    "type"  : "OUT"
  },
  {
    "key" : "test1",
    "value" : 16,
    "type"  : "OUT"
  },
  {
    "key" : "test1",
    "value" : 8,
    "type"  : "IN"
  },
  {
    "key" : "test2",
    "value" : 32,
    "type"  : "OUT"
  },
  {
    "key" : "test2",
    "value" : 16,
    "type"  : "IN"
  },
  {
    "key" : "test2",
    "value" : 8,
    "type"  : "OUT"
  },  
];

//group by key
const groupBy = function(xs, key) {
  return xs.reduce(function(rv, x) {
    (rv[x[key]] = rv[x[key]] || []).push(x);
    return rv;
  }, {});
};

const grouped = groupBy(data,"key");

for (const [key, value] of Object.entries(grouped))
{
    let x = value.filter(({type}) => type === 'OUT')
    .reduce((sum, record) => sum + record.value)
  console.log(x);
}
//const filtered = grouped.filter(({type}) => type === 'OUT');




console.log(Object.values(grouped));

Question 1:
Why does the reduce give me the wrong sum for type OUT?

Question 2:
Is there a way to consider both types (IN, OUT) without doing the same procedure again?

>Solution :

You can combine the grouping + counting in 1 reduce() if you set the default value to 0, you can always add (or remove) the value from the current key (type)

const data = [{"key" : "test1", "value" : 32, "type"  : "OUT"}, {"key" : "test1", "value" : 16, "type"  : "OUT"}, {"key" : "test1", "value" : 8, "type"  : "IN"}, {"key" : "test2", "value" : 32, "type"  : "OUT"}, {"key" : "test2", "value" : 16, "type"  : "IN"}, {"key" : "test2", "value" : 8, "type"  : "OUT"}, ];

const res = data.reduce((p, c) => {
  (p[c['key']] = p[c['key']] || { ...c, value: 0 });
   
  p[c['key']].value = 
      (c.type === 'IN') 
          ? (p[c['key']].value + c.value)
          : (p[c['key']].value - c.value);
  
  return p;
},{});

console.log(res)

Output:

{
  "test1": {
    "key": "test1",
    "value": -40,
    "type": "OUT"
  },
  "test2": {
    "key": "test2",
    "value": -24,
    "type": "OUT"
  }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading