【问题标题】:Recursive version of listToArray functionlistToArray 函数的递归版本
【发布时间】:2019-12-30 12:19:00
【问题描述】:

我是 Javascript 的新手。目前我正在阅读 Marijn Haverbeke 的 Eloquent Javascript,我尝试编写一个从列表中生成数组的函数。有一个非常简单的方法可以通过循环来做到这一点:

function listToArray(list) {
  let array = [];
  for (let node = list; node; node = node.rest) {
    array.push(node.value);
  }
  return array;
}

但是我想用递归的方式写这个。我试着这样说:

列表:

{
  value: 1,
  rest: {
    value: 2,
    rest: {
      value: 3,
      rest: null
    }
  }
}

功能:

function recursiveNth(list) {
  let array = [];
  if (list.rest == null) {
    array.push(list.value);
    return array;
  } else {
    array.push(list.value);
    return recursiveNth(list.rest);
  }
}

输出:

[3]

【问题讨论】:

  • 您可以将array 作为参数移交给recursiveNth。否则,您会在每次调用时失去状态。

标签: javascript function recursion


【解决方案1】:

您的问题是,每次递归时,您都会创建一个 new 数组,然后将其推入该 new 数组,但是,您永远不会进一步添加到这些数组中递归调用。所以,一旦你最终遇到你的基本情况和return array,你就将[3]返回给你的函数的调用者,即return recursiveNth(list.rest);中的recursiveNth(list.rest);。然后计算为return [3]。这个循环一直持续到您的 recursiveNth(); 方法的原始调用者,从而将 [3] 作为您的结果。

相反,您可以返回单个数组并使用.concat() 添加到该数组,方法是进一步调用recursiveNth,如下所示:

const list = { value: 1, rest: { value: 2, rest: { value: 3, rest: null } } };

function recursiveNth(list) {
  if (list.rest == null) {
    return [list.value];
  } else {
    return [list.value].concat(recursiveNth(list.rest));
  }
}

console.log(recursiveNth(list));

【讨论】:

  • 是的,你是对的。我的元素每次都被推入新数组。现在我可以看到我的错误了。我真的很喜欢你的回答,它简单明了。谢谢。
  • 这里的基本情况可能应该使用return [list.value],将元素包装在一个数组中,这样单元素列表就会像多元素列表一样返回数组。
【解决方案2】:

您可以返回值加上递归调用的结果或一个空数组。

主要功能是检查list 是否有truthy 值,例如对象或任何转换为​​布尔值的值是true,并在这种情况下在数组中返回属性value具有rest 属性的递归调用的扩展 (spread syntax ...) 结果。

如果你得到一个falsy 值,与truthy 相反,比如undefinednull,那么只返回一个空数组。这是退出条件检查后的返回值。

要可视化递归函数的各个部分,您需要以下部分(抽象伪代码):

function r(value)
    if (exitCondition) return someValue;         // or an empty data structure
    return value + result of call of r(newValue) // this result can be another data structure
}

对于下面的方法,退出条件被否定,如果没有找到退出值,它会进入一个值和recusion的结果。

function recursive(list) {
    return list
        ? [list.value, ...recursive(list.rest)]
        : [];
}

var list = { value: 1, rest: { value: 2, rest: { value: 3, rest: null } } };

console.log(recursive(list));

【讨论】:

  • “我是 Javascript 新手” - 一个 ES6 特性的答案,但没有任何进一步的解释或指向良好文档的链接或至少是特性的名称...
  • @Andreas:对于新手来说,为什么 ES6 功能比旧功能更适用?我现在在任何其他类型之前教授箭头函数,并从一开始就使用休息/扩展运算符。
  • @ScottSauyet 因为 Eloquent JavaScript 和大部分初学者教程都没有讨论 ES6/7 或任何更新的东西 (tc39)。
  • @Andreas:当前版本的 Eloquent JavaScript 经常使用箭头函数,介绍 async-await,描述 rest 和 spread,解释模板文字,但我记得没有尝试将 ES6 功能与旧功能区分开来。任意教程当然是混杂的,但很多使用 ES6。
  • @Andreas 我确实相信“Eloquent JavaScript”在第二章或第三章中引入了箭头函数。
猜你喜欢
  • 2021-11-29
  • 1970-01-01
  • 2017-11-13
  • 1970-01-01
  • 2021-11-10
  • 1970-01-01
  • 2013-03-08
  • 2012-06-07
  • 2012-01-26
相关资源
最近更新 更多