【问题标题】:Recursive Javascript function using arguments property gives the correct answer, but returns undefined使用 arguments 属性的递归 Javascript 函数给出了正确的答案,但返回 undefined
【发布时间】:2018-06-10 21:52:46
【问题描述】:

我正在构建一个代数计算器,并且正在研究一个递归函数来过滤多项式中的类似项。下面的函数的工作原理是它产生所需的类似术语的数组。我可以通过向函数添加一个 console.log 语句来验证这一点。但是,由于某种原因,该函数不会返回输出。它返回“未定义”。

我的想法是递归调用链应该以如下所示的结束条件终止,然后将返回的参数 [1] 数组通过堆栈传递。

我在这里读到过类似的问题,人们忘记在一个或多个地方放置退货声明。但是,在我的代码中,我有一个带有结束条件和递归函数调用的 return 语句。这可能是我缺少的一些简单的东西。

var filterLikeTerms = function (terms) { //takes an array of terms, optional second argument is an array of arrays of similar terms
  if (!arguments[1]) arguments[1] = []; //Initilizes the second argument if none is given
  if (terms.length == 0) return arguments[1]; //End condition
  arguments[1].push(terms.filter(term => terms[0].toString() === term.toString())); //Adds similar terms to the 2nd argument array
  terms = terms.filter (term => terms[0].toString() !== term.toString()); //shortens the terms array to exclude the like terms filtered above
  return filterLikeTerms(terms, arguments[1]); //recursive function call
}

【问题讨论】:

  • 张贴你打电话给filterLikeTerms的东西?您在必须作为字符串传入的属性上调用 .toString。您不能将 7x + 1 作为值传入。它已经是一个字符串。第二个注意事项,似乎代码试图变得聪明。退后一步,让遍历变得简单,然后再进行优化。
  • 也许我不明白这个问题,但是当我输入console.log(filterLikeTerms(['A', 'B', 'C', 'D'])) 时,它会打印数组数组而不是未定义的......
  • 您不能将参数arguments 传递给该方法,因为它只接受一个参数:terms。我认为您需要使该方法接受2个参数filterLikeTerms(terms, arguments)。该过程的示例可以使您的问题更容易理解,例如示例输入和预期输出。
  • @Eaton 非箭头函数支持通过访问函数内可用的arguments 对象,使用可变数量的参数调用,不一定声明为形式参数。不建议声明名为arguments 的参数!

标签: javascript recursion return arguments


【解决方案1】:

在 ES6 中:

const filterLikeTerms=terms=>[...(new Set(terms))]

【讨论】:

    【解决方案2】:

    工作更聪明,而不是更努力

    尽量不要让不必要的变量、赋值或逻辑条件伤脑筋——一个简单的递归函数和简单的相等测试

    const eq = x => y =>
      x === y
    
    const neq = x => y =>
      x !== y
    
    const filterLikeTerms = ([ x, ...xs ]) =>
      x === undefined
        ? []
        : [ xs.filter (eq (x)) ]
          .concat (filterLikeTerms (xs.filter (neq (x))))
    
    const data =
      ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'a', 'b']
    
    console.log (filterLikeTerms (data))
    // [ [ a, a, a ]
    // , [ b, b ]
    // , [ c ]
    // , [ d ]
    // ]

    灵活实施

    如果您想更改项目的比较和分组方式,请更改 eqneq

    // for example ...
    const eq = x => y =>
      x.toString() === y.toString()
    
    const neq = x => y =>
      x.toString() !== y.toString()
    

    如果您想像在原始代码中那样使用 accumulator 参数,那也可以 - 对于非常大的输入,可以轻松地将这种形式设置为 stack-safe

    const filterLikeTerms = ([ x, ...xs ], acc = []) =>
      x === undefined
        ? acc
        : filterLikeTerms ( xs.filter (neq (x))
                          , acc.concat ([ xs.filter (eq (x)) ])
                          )
    

    更智能地工作

    正确的尾调用(就在上面)使我们能够处理大量数据输入,但我们的函数效率非常低,因为为列表中的每个项目运行多个过滤器。我们可以通过使用Map 进行显着改进——现在我们只触摸原始输入中的每个项目一次

    const filterLikeTerms = ([ x, ...xs ], acc = new Map) =>
      x === undefined
        ? Array.from (acc.values ())
        : acc.has (x)
          ? filterLikeTerms (xs, acc.set (x, [x].concat (acc.get (x))))
          : filterLikeTerms (xs, acc.set (x, [x]))
    
    const data =
      ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'a', 'b']
    
    console.log (filterLikeTerms (data))

    不要停止学习,但

    您可以自己制作各种精美的东西。以下是我写的与此答案相关的一些内容:

    【讨论】:

      猜你喜欢
      • 2023-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-02
      • 1970-01-01
      • 2013-09-29
      • 2020-10-04
      • 1970-01-01
      • 2020-09-12
      相关资源
      最近更新 更多