首页 > 解决方案 > 使用递归迭代数组的 Closure

问题描述

我试图用 clousure 做一个递归函数,但工作量不大。

我试图从数组中添加每个数字以最终返回 [1,2,3,4,5,6,7,8] 但只是返回我 [1,2,5] 奇怪的是我在里面放了一个 console.log否则它会打印我所有的数字。

你能解释一下为什么会这样吗

var array = [1, 2, [3, 4], 5, [6, [7, 8]]]; // --> 1,2,3,4,5,6,7,8
function recursiveArrayPrint(array) {
  let resultado = []
  return function iterator() {
    for (let i = 0; array.length > i; i++) {
      if (Array.isArray(array[i])) {
        recursiveArrayPrint(array[i])()
      } else {
        console.log(array[i])
        resultado.push(array[i])
      }
    }
    return resultado
  }
}
const test = recursiveArrayPrint(array);
console.log('test: ',test())

在此处输入图像描述

标签: javascriptrecursion

解决方案


程序中的错误

  1. resultado被声明recursiveArrayPrint
  2. iterator你调用里面,每次都会recursiveArrayPrint创建一个新的resultado
  3. 只有最外层resultadoreturned
function recursiveArrayPrint(array) {
  let resultado = []                         // #1
  return function iterator() {
    for (let i = 0; array.length > i; i++) {
      if (Array.isArray(array[i])) {
        recursiveArrayPrint(array[i])()      // #2
      } else {
        console.log(array[i])
        resultado.push(array[i])
      }
    }
    return resultado                         // #3
  }
}

怎么修

function recursiveArrayPrint(array) {
                                               // no need for resultado
  function* iterator() {                       // use generator
    for (let i = 0; array.length > i; i++) {
      if (Array.isArray(array[i])) {
        yield *recursiveArrayPrint(array[i])   // yield
      } else {
        yield array[i]                         // yield, not console.log
                                               // no need for resultado
      }
    }                                          
                                               // no need for resultado
  }
  return iterator()
}

const arr = [1, 2, [3, 4], 5, [6, [7, 8]]]

for (const x of recursiveArrayPrint(arr))
  console.log(x)

1
2
3
4
5
6
7
8

我们可以做得更好

  1. recursiveArrayPrint不是一个好名字。我们已经console.log从迭代中解开了影响,调用者可以自由决定如何处理输出。我们可以直接调用recursiveArray
  2. 内部函数iterator现在有点没用了。不再需要这种抽象
  3. forloop withi很容易出错。我们可以使用for..of循环以更清晰的方式编写它

function* recursiveArray(array)
{ for (const x of array)
    if (Array.isArray(x))
      yield *recursiveArray(x)
    else
      yield x
}

const arr = [1, 2, [3, 4], 5, [6, [7, 8]]]

for (const x of recursiveArray(arr))
  console.log(x)

如果您希望将扁平数组作为返回值,JavaScript 提供了Array.from将任何可迭代对象转换为数组的方法 -

console.log(Array.from(recursiveArray(arr)))
[1,2,3,4,5,6,7,8]

不仅适用于数组

  1. 我们可以重命名recursiveArraytraverse,它可以作为通用函数运行
  2. 我们不是假设第一个输入是一个数组,而是先检查isArray 然后再运行for..of循环。否则简单地产生输入

function* traverse(t)
{ if (Array.isArray(t))
    for (const x of t)
      yield *traverse(x)
  else
    yield t
}

const arr = [1, 2, [3, 4], 5, [6, [7, 8]]]

for (const x of traverse(arr))
  console.log(x)
 

1
2
3
4
5
6
7
8

从长远来看,编写健壮的函数将对您有所帮助。traverse现在可以很容易地扩展为逐步遍历对象或其他可迭代对象。现在,当给出非数组输入而不是错误时,我们会得到一个合理的结果 -

for (const x of traverse(123))
  console.log(x)
123

推荐阅读