看到了这样一道题目,描述如下:
已知如下数组:
var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];
编写一个程序将数组扁平化并去除其中重复部分数据,最终得到一个升序且不重复的数组
有几种解决方法,主要是扁平化的不同,去重和升序的做法都一样,利用了ES6的Set对象和数组sort方法,如果有兴趣可以另行研究,这里主要研究数组扁平化。
所谓数组的扁平化,是将一个嵌套多层的数组 (嵌套可以是任何层数)转换为只有一层的数组。
方法一
var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];
Array.from(new Set(arr.flat(Infinity))).sort((a, b) => a - b)
//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
主要是使用了JS内置的flat方法,这个方法本身就是用于实现扁平化的。
方法二
var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];
Array.from(new Set(arr.toString().split(','))).map(Number).sort((a, b) => a - b)
//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
这个思路比较奇异,使用toString()会把数组直接转成逗号分割的元素字符串:
var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];
arr.toString() // "1,2,2,3,4,5,5,6,7,8,9,11,12,12,13,14,10"
可以看到,实际上这实际就已经实现了扁平化了。然后再使用split()进行逗号分隔,就得到了扁平化后的数组:
var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];
arr.toString().split(',') // [1,2,2,3,4,5,5,6,7,8,9,11,12,12,13,14,10]
然后再去重、升序即可,综合起来便是第一个代码段落写的那样。
方法三
我也尝试自己实现去扁平化,代码如下:
var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];
function flat(arr) { //扁平化函数let results = [];let pushResult = function (ele) { // 向结果数组写入元素if (ele instanceof Array) {for (let i of ele) pushResult(i); // 如果为数组,遍历每个元素,进行递归} else {results.push(ele);}}arr.map(pushResult);results = Array.from(new Set(results)).sort((a, b) => a - b); // 去重、排序,分别使用Set对象和sort方法return results;
}
flat(arr); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
对比和总结
第一种方法扁平化方法使用了内置函数flat(),这个方法要把第二种方式和自己写的扁平化函数要更厉害些,它能够传递一个参数,用来指明将第几层的数组“拉平”。比如本例里的 flat(Infinity) ,Infinity表示无论是嵌套的第几层,都给予“拉平”。
第二种方式属于思路比较巧妙,把问题的方向转化了一下,变成了数组与字符转换,这种思维也值得学习。但是和自己编写的扁平化函数一样,对于要扁平化的层数无法控制,而是暴力地全部“拉平”。
对于flat函数的介绍,可以参考这篇博客 es6之数组的flat(),flatMap()