如何使用递归在JavaScript中扁平化数组

709 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情

什么是递归?

递归只是意味着一个调用自己的函数。你可能会立即问,如果一个函数继续调用自己,它会是一个无限循环吗?是的——你是对的!

为了解决这个问题,一旦我们完成任务,我们使用一些条件(很可能是if条件)来停止递归函数调用。这些条件被称为基本案例

让我们从一个例子开始。假设我想打印从1到N的数字(包括)。通常,你会为它写一个for循环,对吗?类似的东西:

截屏2022-08-28 下午10.54.14.png

打印1到N的功能(迭代解决方案)

如果我想用递归编写代码来打印1到N怎么办?

要为上述内容编写递归函数,我们必须问以下两个问题:

  1. 我们的递归函数什么时候应该停止?答案:在达到N+1时,因为我们必须从1到N (包括) 打印。
  2. 我们的递归函数应该做的实际工作是什么?答案:将值打印到控制台。

因此,简而言之,继续打印值,直到我们达到N+1。

根据我们刚才讨论的第二个问题,我们的代码应该看起来像这样:

截屏2022-08-28 下午10.54.49.png

上面的代码也打印1到N(5),对吗?这条代码的实际工作是将值打印到控制台。

现在,与其手动调用相同的函数,不如让代码为我们做。类似的东西:

截屏2022-08-28 下午10.55.12.png

如果您仔细观察上述代码,第6行print1ToNo(currentValue + 1)正在使用新值(无论当前值是多少,加1,即currentValue + 1)调用相同的函数。它一直在这样做,直到当前值超过N,因为那是我们告诉它返回的时候。现在,这就是递归的含义。

如何思考递归方式

现在,让我们回到我们的主要问题——我们需要扁平化一个阵列。假设我们只有一个层次的嵌套(当然,我们可以有多个嵌套,但现在我们将处理一个)。数组应该看起来像这样:

运球射击---1-4

示例输入 - 1 级嵌套

我们将按索引浏览输入数组索引。

索引0,值=1

索引0包含一个数字(值=1)。它只是一个数字,而不是一个数组。我们需要扁平化数字吗?不!它们将成为输出阵列的一部分。也就是说,我们不需要对数字做任何特别的事情,我们只特别关注数组。

因此,我们的规则是,如果是一个数字,将其推送到输出数组,然后转到下一个索引(即此处的索引1)。

索引1,值=2

索引1还包含一个数字(值=2)。我们需要扁平化数字吗?不!它们将成为输出阵列的一部分。 因此,按照我们的规则,如果是数字,请将其推送到输出数组,然后转到下一个索引(此处索引2)。

索引2,值=[3,4]

现在,索引2是一个数组([3,4]), 而不是数字。所以现在我们必须想办法把它夷为平地。

如果我给你一个数组[3,4],并告诉你把它弄平呢?您将像我们之前一样开始按索引浏览数组元素索引。然后你可能会意识到3只是一个数字,所以把它推到输出数组,然后转到下一个索引。

Well in the next index, 4 is also just a number, so push it to the output array. And we're done! Well, why don't you do that same on index 2 ( [ 3, 4 ] )  of our input array, then?

你一定在想,好吧,这么说很容易!如何在代码中做到这一点!?这就是递归进入画面的地方。 每当我们遇到数组时,我们都会告诉递归函数将该数组作为新的输入,并为我们解决它。

将所有内容置于上下文中,如果只是一个数字,不要做任何事情,只需将该数字推送到我们的输出数组,然后转到下一个索引。

如果是数组,则将该数组作为新输入,并开始做我们之前所做的。(我们将使用递归来完成这一部分)

问题的解决方案

好吧,提醒一下,这是我们的问题:

您将获得一个数组,其中包含数字和嵌套数字数组。您的工作是返回一个新的数组,该数组以线性方式包含所有数字,而无需任何嵌套。请记住,筑巢可以是任何级别的深度。

以下是使用递归解决我们问题的办法:

截屏2022-08-28 下午10.55.47.png

解决方案 - 代码

如果您仔细查看上述代码片段中名为递归的函数,我们正在检查我们当前所在的数组元素是否是数组。名为**index的变量用于表示我们在inputArray中的当前索引。**

如果它不是数组,我们只需将该元素推送到我们的输出数组中,然后转到下一个索引。否则,我们将使用索引变量指向的数组开始一个新的函数调用(递归)。

这段代码适用于任何级别的嵌套,而不仅仅是1级的嵌套!为什么会这样?每当我们找到一个数组而不是一个数字时,我们都会发起一个新的递归调用,该数组作为递归调用的输入。

因此,无论我们有多少嵌套数组,递归都会持续下去,直到我们找到一个数字,这样我们就可以开始将其推送到输出数组!

这就是递归在幕后的工作原理(对于上一个示例):

运球射击---1

事情是如何完成的!

结论

现在,您知道如何使用递归扁平化数组。当涉及到时间和空间的复杂性时,递归是一种不适合的方法。