【问题标题】:Trying to find even and odd number count using reduce尝试使用reduce查找偶数和奇数计数
【发布时间】:2019-05-10 10:07:01
【问题描述】:

我正在尝试使用 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 }

【问题讨论】:

  • 您还没有发布更多内容吗?因为从表面上看,我不认为这是返回有多少奇数和偶数。我读这个是因为他们想要一个函数来计算给定数组中每个唯一值的出现次数。例如[1,1,2,4,4,4] 将返回 {1:2,2:1,4:3} 类似于 php 的 array_count_values

标签: javascript arrays reduce higher-order-functions


【解决方案1】:

您正在将 oddCountevenCount 初始化为 0 inside 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 }

【讨论】:

  • 关于第一个 sn-p :不,这不是你应该如何使用reduce。如果你这样做,只需使用 for...of 循环。
  • 你不需要这些变量,使用来自acc的计数器
  • @SzymonD 你不需要它们,但这就是 OP 的代码正在做的事情,所以我将展示如何通过对 OP 代码的最小更改来修复它。当然,最好只检查累加器上的属性,正如您在较低的 sn-p 中看到的那样。
【解决方案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})
}

这是按照你想要的方式解决,根据日志。如果您按照命令进行操作,我认为它实际上应该是这样的:

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;
  }, {})
}

您最初的尝试依赖于返回“奇数”或“偶数”的回调函数来工作。上面的代码可以与返回任何值的函数一起使用

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      我将从一个通用函数开始,用于增加对象 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 }
        )

      将其插入reducecountBy 基本上会自行写入 -

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

      【讨论】:

        【解决方案5】:

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

        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 }

        【讨论】:

          猜你喜欢
          • 2016-09-16
          • 1970-01-01
          • 2023-03-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-03-03
          相关资源
          最近更新 更多