1
+ // 实现数组扁平化的6种方式
2
+ // 数组相关的应用————如何实现数组扁平化。数组扁平化在一些多维数组的应用场景中会出现,我将围绕6种方式来实现它。
3
+ // 此外,关于数组除了扁平化也有其他问题,比如数组去重等,也是面试中经常会问到的。目的是将扁平化作为一个切入点,这种思路对于你解决
4
+ // 其他类似的问题也是一个很好的启发。
5
+ // 开始前先思考几个问题:
6
+ // 1.怎样用最普通的方法解决数组扁平化问题?
7
+ // 2.ES6 里面是否有一些高级的方法能够直接实现?
8
+
9
+ // 扁平化的实现
10
+ // 数组的扁平化其实就是将一个嵌套多层的数组 array (嵌套可以是任何层数)转换为只有一层的数组。举个简单的例子,假设有个名为 flatten
11
+ // 的函数可以做到数组扁平化,效果如下面这段代码所示。
12
+ var arr = [ 1 , [ 2 , [ 3 , 4 , 5 ] ] ] ;
13
+ console . log ( flatten ( arr ) ) ; // [1, 2, 3, 4, 5]
14
+ // 其实就是把多维的数组“拍平”,输出最后的一维数组。
15
+
16
+ // 方法一:普通的递归实现
17
+ // 普通的递归思路很容易理解,就是通过循环递归的方式,一项一项地去遍历,如果每一项还是一个数组,那么就继续往下遍历,利用递归程序的方法,
18
+ // 来实现数组的每一项的连接。
19
+ var a = [ 1 , [ 2 , [ 3 , 4 , 5 ] ] ] ;
20
+ function flatten ( arr ) {
21
+ let result = [ ] ;
22
+
23
+ for ( let i = 0 ; i < arr . length ; i ++ ) {
24
+ if ( Array . isArray ( arr [ i ] ) ) {
25
+ result = result . concat ( flatten ( arr [ i ] ) ) ;
26
+ } else {
27
+ result . push ( arr [ i ] ) ;
28
+ }
29
+ }
30
+ return result ;
31
+ }
32
+ flatten ( a ) ;
33
+ // 这段代码核心就是循环遍历过程中的递归操作,就是在遍历过程中发现数组元素还是数组的时候进行递归操作,把数组的结果通过数组的 concat 方法
34
+ // 拼接到最后要返回的 result 数组上,那么最后输出的结果就是扁平化后的数组。
35
+
36
+ // 方法二:利用 reduce 函数迭代
37
+ // 从上面普通的递归函数中可以看出,其实就是对数组的每一项进行处理,那么我们其实也可以用 reduce 来实现数组的拼接,从而简化第一种方法的
38
+ // 代码,改造后的代码如下所示。
39
+ var arr = [ 1 , [ 2 , [ 3 , 4 , 5 ] ] ] ;
40
+ function flatten ( arr ) {
41
+ return arr . reduce ( function ( prev , next ) {
42
+ return prev . concat ( Array . isArray ( next ) ? flatten ( next ) : next ) ;
43
+ } , [ ] ) ;
44
+ }
45
+ console . log ( flatten ( arr ) ) ;
46
+ // 我们可以看到reduce的第一个参数用来返回最后累加的结果,思路和第一种递归方法是一样的,但是通过使用reduce之后代码变得更简洁了,也同样
47
+ // 解决了扁平化的问题。
48
+
49
+ // 方法三:扩展运算符实现
50
+ // 这个方法的实现,采用了扩展运算符和some的方法,两者共同使用,达到数组扁平化的目的。
51
+ var arr = [ 1 , [ 2 , [ 3 , 4 , 5 ] ] ] ;
52
+ function flatten ( arr ) {
53
+ while ( arr . some ( item => Array . isArray ( item ) ) ) {
54
+ arr = [ ] . concat ( ...arr ) ;
55
+ }
56
+ return arr ;
57
+ }
58
+ console . log ( flatten ( arr ) ) ;
59
+ // 从执行的结果中可以发现,我们先用数组的some方法把数组中仍然是数组的项过滤出来,然后执行concat操作,利用 ES6 的展开运算符,将其拼接到
60
+ // 原数组中,最后返回原数组,达到了预期的效果。
61
+ // 前三种实现数组扁平化的方式其实是最基本的思路,都是通过最普通递归思路衍生的方法,尤其是前两种实现方法比较类似。值得注意的是reduce方法,
62
+ // 它可以在很多应用场景中实现,由于reduce这个方法提供的几个参数比较灵活,能解决很多问题,所以是值得熟练使用并且精通的。
63
+
64
+ // 方法四:split 和 toString 共同处理
65
+ // 我们也可以通过 split 和 toString 两个方法,来共同实现数组扁平化,由于数组会默认带一个 toString 的方法,所以可以把数组直接转换成逗号
66
+ // 分隔的字符串,然后再用 split 方法把字符串重新转换为数组
67
+ var arr = [ 1 , [ 2 , [ 3 , 4 , 5 ] ] ] ;
68
+ function flatten ( arr ) {
69
+ return arr . toString ( ) . split ( ',' ) ;
70
+ }
71
+ console . log ( flatten ( arr ) ) ;
72
+ // 通过这两个方法可以将多维数组直接转换成逗号连接的字符串,然后再重新分隔成数组。
73
+
74
+ // 方法五:调用 ES6 中的 flat
75
+ // 我们还可以直接调用 ES6 中的 flat 方法,可以直接实现数组扁平化。先来看下 flat 方法的语法:
76
+ // arr.flat([depth])
77
+ // 其中 depth 是 flat 的参数,depth 是可以传递数组的展开深度(默认不填、数值是1),即展开一层数组。那么如果多层的该怎么处理呢?参数也可以
78
+ // 传进 Infinity,代表不论多少次都要展开。
79
+ var arr = [ 1 , [ 2 , [ 3 , 4 , 5 ] ] ] ;
80
+ function flatten ( arr ) {
81
+ return arr . flat ( Infinity ) ;
82
+ }
83
+ console . log ( flatten ( arr ) ) ;
84
+ // 可以看出,一个嵌套了两层的数组,通过将 flat 方法的参数设置为 Infinity,达到了我们预期的效果。其实同样也可以设置成2,也能实现这样的效果。
85
+ // 因此,你在编程过程中,发现对数组的嵌套层数不确定的时候,最好直接使用 Infinity,可以达到扁平化。
86
+
87
+ // 方法六:正则和 JSON 方法共同处理
88
+ // 我们在第四种方法中已经尝试了用 toString 方法,其中仍然采用了将 JSON.stringify 的方法先转换为字符串,然后通过正则表达式过滤掉字符串中
89
+ // 的数组的方括号,最后再利用 JSON.parse 把它转换成数组。
90
+ let arr = [ 1 , [ 2 , [ 3 , 4 , 5 ] ] ] ;
91
+ function flatten ( arr ) {
92
+ let str = JSON . stringify ( arr ) ;
93
+ str = str . replace ( / ( \[ | \] ) / g, '' ) ;
94
+ str = '[' + str + ']' ;
95
+ return JSON . parse ( str ) ;
96
+ }
97
+ console . log ( flatten ( arr ) ) ;
98
+ // 通过这个在线网站 https://regexper.com/ 可以把正则分析成容易理解的可视化的逻辑脑图。
0 commit comments