尝试使用 reduce 查找偶数和奇数计数

Trying to find even and odd number count using reduce

我正在尝试使用 reduce 解决以下问题,但我无法获得对象中偶数和奇数的正确计数。

有人可以指导我我的代码有什么问题吗?

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 }

您正在将 oddCountevenCount 初始化为 0 reduce 回调的 中,因此在每次迭代中, 你的

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

只会将 evenCountoddCount 递增到 1。相反,在 回调之外初始化计数,以便对它们的更改在 reduce 回调的多次调用中保持不变:

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 }

或者,您可以通过检查累加器上已有的 属性 的值来完全避免外部变量:

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 }

正如 CertainPerformance 所说,您正在重新初始化用于计数的变量。此外,您正在发送一个额外的参数来减少,不应该在那里。 Reduce 只需要 2 个参数。

这就是我的处理方式

function countBy(arr, fn) {
  return arr.reduce(function(acc, nums) {
   console.log(nums, fn(nums))
    if(fn(nums) === "even"){
      acc.even ++;
    } else {
      acc.odd ++;
    }
    return acc
  }, {odd: 0, even: 0})
}

这个就是按照你想要的方式解决,根据log。如果您按照命令进行操作,我认为它实际上看起来像这样:

function countBy(arr, fn) {
  return arr.reduce(function(acc, val) {
    let key = fn(val);
    if (!acc[key]) {
      acc[key] = 1;
    } else {
      acc[key]++;
    }
    return acc;
  }, {})
}

您最初的尝试依赖于返回 'odd' 或 'even' 的回调函数。上面的代码可以与返回任何值的函数一起使用

除了 Array.reduce 之外,您还可以通过 Array.forEach 和辅助函数以稍微不同的方式解决此问题:

const isEvenOrOdd = n => n % 2 ? "even" : "odd"
const propCount = (prop, obj) => obj[prop] = (obj[prop] || 0) + 1

const countBy = (arr, fn, obj={}) => {
  arr.forEach(x => propCount(isEvenOrOdd(x), obj))
  return obj
}

console.log(countBy([1, 2, 3, 4, 5], isEvenOrOdd));

我将从一个通用函数开始,用于在对象 o

上递增键 k

const incr = k => ({ [k]: val = 0, ...o }) =>
  ({ ...o, [k]: val + 1 })
  
const incrFoo =
  incr ("foo")

console .log
  ( incrFoo ({})
    // { foo: 1 }
    
  , incrFoo ({ bar: 100 })
    // { bar: 100, foo: 1 }
    
  , incrFoo ({ foo: 3, bar: 100 })
    // { bar: 100, foo: 4 }
    
  , incr ("even") ({ odd: 2, even: 2 })
    // { odd: 2, even: 3 }
  )

插到reduce上,countBy基本就是自己写-

const incr = k => ({ [k]: val = 0, ...o }) =>
  ({ ...o, [k]: val + 1 })
  
const countBy = (f, xs = []) =>
  xs .reduce
    ( (acc, x) => incr (f (x)) (acc)
    , {}
    )

console .log
  ( countBy
      ( x => x & 1 ? "odd" : "even"
      , [ 1, 2, 3, 4, 5 ]
      )
      // { even: 2, odd: 3 }

  , countBy
      ( x => x
      , [ 'a', 'b', 'b', 'c', 'c', 'c' ]
      )
      // { a: 1, b: 2, c: 3 }
  )

高阶函数不限于 mapfilterreduce - 使用延续组合器,下面的 $,我们显示 countBy 作为递归函数。作为一个额外的优势,这个实现接受任何 iterable 作为输入;不仅是数组。

const incr = k => ({ [k]: val = 0, ...o }) =>
  ({ ...o, [k]: val + 1 })
  
const $ = x => k =>
  k (x)
  
const None =
  Symbol ()
  
const countBy = (f, [ x = None, ...xs ]) =>
  x === None
    ? {}
    : $ (f (x))
        (key => $ (countBy (f, xs)) (incr (key)))
  
console .log
  ( countBy
      ( x => x & 1 ? "odd" : "even"
      , [ 1, 2, 3, 4, 5 ]
      )
      // { even: 2, odd: 3 }

  , countBy
      ( x => x
      , "mississippi"
      )
      // { p: 2, s: 4, i: 4, m: 1 }
  )

最简单的方法是创建一个函数来检查偶数,例如

const isEven = n => n%2 === 0;

初始化对象结果应该是这样的

{odd: 0, even: 0}

var nums = [1, 2, 3, 4, 5];
const isEven = n => n%2 == 0;
const result = nums.reduce((acc, curr) => {
  if(isEven(curr)) acc.even++;
  else acc.odd++;
  
  return acc;  
}, {odd: 0, even: 0})
console.log(result); // should log: { odd: 3, even: 2 }