Trying to find even and odd number count using reduce

I’m trying to solve the problem below using reduce but I’m not able to get the correct count of even and odd numbers in the object.

Can someone please guide me on what’s wrong with my code?

Create a function countBy that accepts an array and a callback, and returns an object. countBy will iterate through the array and perform the callback on each element. Each return value from the callback will be saved as a key on the object. The value associated with each key will be the number of times that particular return value was returned

function countBy(arr, fn) {
  return arr.reduce(function(acc, nums) {
    // console.log(nums);
    let oddCount = 0
    let evenCount = 0
    console.log(nums, fn(nums))
    if(fn(nums) === "even"){
      evenCount++;
      acc['even'] = evenCount;
    } else {
      oddCount++;
      acc['odd'] = oddCount;
    }
    return acc
  }, {}, 0)
}

function evenOdd(n) {
 if (n % 2 === 0) return "even";
 else return "odd";
}

var nums = [1, 2, 3, 4, 5];
console.log(countBy(nums, evenOdd)); // should log: { odd: 3, even: 2 }

Answer

You’re initializing oddCount and evenCount to 0 inside of the reduce callback, so on every iteration, your

evenCount++;
acc['even'] = evenCount;

is only ever incrementing the evenCount or oddCount to 1. Initialize the counts outside the callback instead, so that changes to them are persistent over multiple calls of the reduce callback:

function countBy(arr, fn) {
  let oddCount = 0
  let evenCount = 0
  return arr.reduce(function(acc, nums) {
    // console.log(nums);
    console.log(nums, fn(nums))
    if (fn(nums) === "even") {
      evenCount++;
      acc['even'] = evenCount;
    } else {
      oddCount++;
      acc['odd'] = oddCount;
    }
    return acc
  }, {}, 0)

}

function evenOdd(n) {
  if (n % 2 === 0) return "even";
  else return "odd";
}
var nums = [1, 2, 3, 4, 5];
console.log(countBy(nums, evenOdd)); // should log: { odd: 3, even: 2 }

Or, you might avoid outer variables entirely, by checking the value of the property already on the accumulator:

const countBy = (arr, fn) => arr.reduce((acc, num) => {
  const prop = fn(num);
  acc[prop] = (acc[prop] || 0) + 1;
  return acc;
}, {});

function evenOdd(n) {
  if (n % 2 === 0) return "even";
  else return "odd";
}
var nums = [1, 2, 3, 4, 5];
console.log(countBy(nums, evenOdd)); // should log: { odd: 3, even: 2 }