34

So I have an array

const records = [
    {
        value: 24,
        gender: "BOYS"
    },
    {
        value: 42,
        gender: "BOYS"
    },
    {
        value: 85,
        gender: "GIRLS"
    },
    {
        value: 12,
        gender: "GIRLS"
    },
    {
        value: 10,
        gender: "BOYS"
    }
]

And I want to get the sum so I used the JavaScript array reduce function and got it right. Here is my code:

someFunction() {
  return records.reduce(function(sum, record){
    return sum + record.value; 
  }, 0);
}

With that code I get the value 173 which is correct. Now what I wanted to do is to get all the sum only to those objects who got a "BOYS" gender.

I tried something like

someFunction() {
  return records.reduce(function(sum, record){
    if(record.gender == 'BOYS') return sum + record.value; 
  }, 0);
}

But I get nothing. Am I missing something here? Any help would be much appreciated.

wobsoriano
  • 12,348
  • 24
  • 92
  • 162

10 Answers10

70

When you return nothing from the reduce function it returns undefined and undefined + 1 === NaN. You should instead filter the array before reducing.

records.filter(({gender}) => gender === 'BOYS')
    .reduce((sum, record) => sum + record.value)
T4rk1n
  • 1,380
  • 12
  • 15
23

You need to return the current sum and not undefined if your condition is not matched.

Otherwise you aren't returning your accumulator to the reduce function and end up adding unefined + record.value when matched or undefined + undefined when it is not matched.

Try this:

<script>
  const records = [{
      value: 24,
      gender: "BOYS"
    },
    {
      value: 42,
      gender: "BOYS"
    },
    {
      value: 85,
      gender: "GIRLS"
    },
    {
      value: 12,
      gender: "GIRLS"
    },
    {
      value: 10,
      gender: "BOYS"
    }
  ];

  function someFunction() {
    return records.reduce(function(sum, record) {
     return (record.gender !== 'BOYS') ? sum : sum + record.value;

    }, 0);
  }
  console.log(someFunction());
</script>
Alexander Higgins
  • 6,765
  • 1
  • 23
  • 41
16

If the gender is 'GIRLS' it will return undefined. Add an else statement that returns sum and it should fix the problem.

const records = [
    {
        value: 24,
        gender: "BOYS"
    },
    {
        value: 42,
        gender: "BOYS"
    },
    {
        value: 85,
        gender: "GIRLS"
    },
    {
        value: 12,
        gender: "GIRLS"
    },
    {
        value: 10,
        gender: "BOYS"
    }
]

function someFunction() {
  return records.reduce(function(sum, record){
    if(record.gender == 'BOYS') return sum + record.value;
    else return sum;
  }, 0);
}

console.log(someFunction())
Mμ.
  • 8,382
  • 3
  • 26
  • 36
8

You should also return the sum when the gender is GIRLS. reduce goes through each item and expects a return value. If you don't return a value, it will be undefined. So after the third iteration, the sum will be undefined.

const sumBoys = records.reduce((sum, record) => {
  if (record.gender.toLowerCase() === 'boys') {
    return sum + record.value;
  }

  return sum;
}, 0);

const records = [{
  value: 24,
  gender: "BOYS"
}, {
  value: 42,
  gender: "BOYS"
}, {
  value: 85,
  gender: "GIRLS"
}, {
  value: 12,
  gender: "GIRLS"
}, {
  value: 10,
  gender: "BOYS"
}];

const sumBoys = records.reduce((sum, record) => {
  if (record.gender.toLowerCase() === 'boys') {
    return sum + record.value;
  }

  return sum;
}, 0);

console.log(sumBoys);
dork
  • 4,396
  • 2
  • 28
  • 56
2

You are trying to retrieve which object is having gender is "BOYS". But some objects having Female gender at that time it will returns undefined.

Try this to avoid that undefined ....

var resSet=records.filter(function(options){
    return options.gender == "BOYS";
}).reduce(function(a,b){
    return a+parseInt(b.value);
},0);

console.log("the sum of boys set is --"+resSet);
SwissCodeMen
  • 4,222
  • 8
  • 24
  • 34
Narendra Manam
  • 161
  • 3
  • 11
2

Well, in case you just want to stick with reduce and don't want to use filter, you can do it this way:

const records = [
    {
        value: 24,
        gender: "BOYS"
    },
    {
        value: 42,
        gender: "BOYS"
    },
    {
        value: 85,
        gender: "GIRLS"
    },
    {
        value: 12,
        gender: "GIRLS"
    },
    {
        value: 10,
        gender: "BOYS"
    }
];

  var res = records.reduce(function(sum, record){
    if(record.gender === 'BOYS') {
       return sum + record.value;
     } else{
        return sum
    }; 
  }, 0);
  console.log(res);
  var res = records.reduce(function(sum, record){
    if(record.gender == 'BOYS') {
       return sum + record.value;
     } else{
        return sum
    }; 
  }, 0);
ABGR
  • 4,631
  • 4
  • 27
  • 49
1

Assuming that if records was empty you want to set an accumulator value that matches your output. Also the definition of empty when records.length === 0 vs when only count of BOYS is 0 might be different.

const defaultValue = 0, target = 'BOYS'
const result = records.reduce( (sum,{gender,value})=>{
   return gender === target ? (sum||0)+value : sum;
},defaultValue);

some fun with reduce and your question: https://jsfiddle.net/gillyspy/021axnsr/8/

gillyspy
  • 1,578
  • 8
  • 14
0

We can use this simplified code

let res= records.reduce(function(a,b){ 
    return (b.gender === "BOYS" && (a+parseInt(b.value))) || a; 
}, 0);
Narendra Manam
  • 161
  • 3
  • 11
0

you got an error because, reduce method iterate.in each element i. array and returns the.accumulated value,

what happen is, when your condition did not meet, the value of accumulator becomes.undefined because you.did not return it.

you need to sum first if it meets the.condition. and outside the if scope return the sum,

Cedrick Campoto
  • 121
  • 1
  • 3
0

Just use only Array.prototype.reduce() and you can solve it by:

const test = records.reduce((a, e) => {
        if (e.gender === "BOYS") {
          return a + e.value;
        } else {
          return a;
        }
      }, 0);
      console.log(test);
V8C40
  • 1
  • 1
  • Answer of the same style given [3 years ago](https://stackoverflow.com/a/62082000/5273255) on this same question – Can O' Spam Aug 01 '23 at 11:41