【问题标题】:Strange behaviour of reduce method in JavaScript?JavaScript中reduce方法的奇怪行为?
【发布时间】:2020-08-14 14:00:08
【问题描述】:

我试图使用函数式编程创建一个偶数的斐波那契数列数组 - 下面的代码

let a = [1, 2];

const r = (n) =>
  Array.from(
    a[a.length - 1] + a[a.length - 2] <= n ?
    a.push(a[a.length - 1] + a[a.length - 2]) && r(n) :
    a
  )
  .filter(v => !(v % 2))
  //.reduce((s, v) => s+=v, 0)

console.log(r(56))

它给出了正确的数组,但是当我想计算总和时(通过注释最后一行使用reduce方法)它给出0作为结果

let a = [1, 2];

const r = (n) =>
  Array.from(
    a[a.length - 1] + a[a.length - 2] <= n ?
    a.push(a[a.length - 1] + a[a.length - 2]) && r(n) :
    a
  )
  .filter(v => !(v % 2))
  .reduce((s, v) => s+=v, 0)

console.log(r(56))

在 Repl.it (Link - https://repl.it/@rahul4sap/1)。但是,当我尝试在 Chrome 开发工具中粘贴相同的内容时,它会给出正确的输出。有人可以帮我解释一下为什么 Chrome 开发工具和 Repl.it 中的行为不同(我在本地节点服务器中看到的行为相同)

另外,如果有人也请帮我解决这个问题会很好(请注意,我想以尽可能多的功能方式解决这个问题)

提前致谢!

【问题讨论】:

  • 请把所有相关代码放在这里,在问题中,所以它是独立的。
  • 不要将命令式代码+= 与函数式成语混用。
  • 你为什么使用Array.from()?您希望通过它实现什么目标?
  • 好的,我明白了。你有一个递归函数 expects 返回一个数组。但是,如果您在末尾添加 .reduce,您的 递归调用 会产生纯数字,因此您会破坏该功能。因此,顶级reduce 仅在空数组上执行。
  • 感谢您指出问题 VLAZ 和@Steve Bennett。有什么方法可以通过函数式编程方式得到结果

标签: javascript node.js ecmascript-6 functional-programming


【解决方案1】:

您可以先分离函数并获取斐波那契数组,然后过滤数组,依此类推。

这种方法通过移交一个新的构建数组来使用递归。

const
    add = (a, b) => a + b,
    f = (n, a = [1, 2]) => a[a.length - 1] + a[a.length - 2] < n
        ? f(n, [...a, a[a.length - 1] + a[a.length - 2]])
        : a,
    r = n => f(n)
        .filter(v => !(v % 2))
        .reduce(add, 0);

console.log(r(56));

【讨论】:

  • 谢谢!但是,我正在寻找单个函数中的解决方案(可能使用递归)。你会试一试吗
  • @Rahul 单个功能不会削减它。好吧,除非您将一个 visible 函数算作一个函数 - 您可以在内部定义一个在外部不可见的递归辅助函数。
【解决方案2】:

考虑一个简单的递归函数,fibs -

const fibs = (n = 0, a = 0, b = 1) =>
  n <= 0
    ? []
    : [ a, ...fibs(n - 1, b, a + b) ]
    
console.log(fibs(10)) // first 10 fib numbers
// [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ]

现在添加您的.filter -

const fibs = (n = 0, a = 0, b = 1) =>
  n <= 0
    ? []
    : [ a, ...fibs(n - 1, b, a + b) ]

const evens =
  fibs(10)
    .filter(n => !(n & 1))

console.log(evens)
// [ 0, 2, 8, 34 ]

现在添加您的.reduce -

const fibs = (n = 0, a = 0, b = 1) =>
  n <= 0
    ? []
    : [ a, ...fibs(n - 1, b, a + b) ]

const sumEvens =
  fibs(10)
    .filter(n => !(n & 1))
    .reduce((r, n) => r + n, 0)
    
console.log(sumEvens)
// 44

要了解如何使用其他函数式编程技术计算斐波那契,请参阅 this recent Q&A


谢谢你。但是我正在寻找一个数组中的推元素(可能在一个函数中),直到满足某些条件(比如创建斐波那契数组,直到最后一个元素小于 100)。

您将n = 0 更改为until = 0 并将循环的退出条件从n &lt;= 0 更改为a &gt; until -

const fibs = (until = 0, a = 0, b = 1) =>
  a > until
    ? []
    : [ a, ...fibs(until, b, a + b) ]

console.log(fibs(100))
// [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 ]

const sumEvens =
  fibs(100)
    .filter(n => !(n & 1))
    .reduce((r, n) => r + n, 0)

console.log(sumEvens)
// 4

【讨论】:

  • 谢谢你。但我正在寻找一个数组中的推元素(可能在单个函数中),直到满足某些条件(比如创建斐波那契数组,直到最后一个元素小于 100)。
  • 嗨 Rahul,这里的答案可以根据您的特定需求进行调整。像您请求的小更改是更改提供的fibs 函数的退出条件的问题。我做了一个编辑,显示了你可以自己轻松完成的事情。
【解决方案3】:

当您知道需要多少个斐波那契数时,您可能会在一行中收到结果。 例如,此代码从前 10 个斐波那契数中过滤偶数并计算它们的总和:

let arr = (n) => [1, 2, ...Array(n-2)].reduce((acc, rec, idx) => (idx < 2) ? [...acc, rec] : [...acc, (acc[idx-2] + acc[idx-1])],[])
.filter(it => !(it % 2))
.reduce((s, v) => s+=v, 0)

console.log(arr(10))

【讨论】:

  • 谢谢塞尔吉奥。同意!!但就我而言,我不知道数字。它应该是动态的,就像在数组中推送斐波那契数,直到条件为真。
猜你喜欢
  • 2015-10-24
  • 1970-01-01
  • 2019-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多