39

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.

11 Answers 11

76

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)
Sign up to request clarification or add additional context in comments.

4 Comments

This is the correct way, could you reformat the code into two lines
The correct way to do it. +1 for that but it doesn't explain the cause for the original bug. Instead it just eliminates it.
@AlexanderHiggins It's because the items were added to undefined so he got NaN (() => {})() + 1 === NaN
Keep in mind that using filter and then reduce introduces additional full iteration over array records. Using only reduce with else branch, like in the other answers, avoids this problem.
24

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>

Comments

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())

Comments

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);

Comments

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);

1 Comment

This answer was given three years earlier
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);

Comments

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/

Comments

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

console.log(data)

Comments

0

We can use this simplified code

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

Comments

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,

Comments

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);

1 Comment

Answer of the same style given 3 years ago on this same question

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.