尝试使用reduce

时间:2018-12-09 06:13:22

标签: javascript arrays reduce higher-order-functions

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

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

  

创建一个函数countBy,它接受一个数组和一个回调,并且   返回一个对象。 countBy将遍历数组并执行   每个元素上的回调。回调中的每个返回值都会   保存为对象上的键。与每个键关联的值   将是返回特定返回值的次数

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 }

5 个答案:

答案 0 :(得分:3)

您正在将oddCount的{​​{1}}和evenCount初始化为0的{​​{1}}内部,因此在每次迭代中,您的

reduce

仅将evenCount++; acc['even'] = evenCount; evenCount递增到oddCount。相反,请在回调外部初始化计数,以便对它们的更改在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 }

答案 1 :(得分:1)

正如SomePerformance所说,您正在重新初始化要用来计数的变量。另外,您还发送了一个额外的参数来减少,该参数不应该存在。 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})
}

根据日志,这是按照您想要的方式解决的。如果您要遵循这些命令,我​​认为它实际上应该是这样的:

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

您的原始尝试依赖于返回“奇数”或“偶数”才能正常工作的回调函数。上面的代码可以与返回任何值的函数一起使用

答案 2 :(得分:0)

除了使用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));

答案 3 :(得分:0)

我将从通用函数开始,该函数用于增加对象k上的键o

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

答案 4 :(得分:0)

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

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 }