4种方式实现数组扁平化

2,915 阅读2分钟

这是某节秋招原题。给的参考实例是:[1, 2, [3, 4, [5, { a: 1 }, [6]]]]。基本思路就是遍历数组拿到每一项,只要每一项的类型是数组就继续遍历扁平化。

这道题看着复杂,里面不仅有数组还有对象。但是其实对象放里面就是唬人的,因为我们在判断是否是数组时不要用typeof就可以避开对象了,用Array.isArray()或者instanceof就ok啦。

实现方式

1.巧用reduce

reduce + 递归

因为reduce函数的参数是previou(上一个)和current(当前),非常适合对数组的元素进行连续操作的情况。

举一个简单的例子熟悉reduce函数:

//对数组元素求和
function sum(arr) {
 return arr.reduce((prev, curr) => {
        return prev + curr; //一开始prev为初始值0,curr为arr[0]
    }, 0); //这是prev的初始值
}

对数组扁平化的话,也是需要对数组进行连续操作的,前一个元素concat后一个元素。

function flat(arr) {
    return arr.reduce((prev, curr) => {
  return prev.concat(Array.isArray(curr) ? flat(curr) : curr); 
    }, []);
}

2.巧用正则

将数组扁平化就是要将数组中嵌套的数组拿到最外层数组,对吧?这里有一个很巧的思路就是将数组变为string类型用正则把所有的[]去掉。

function flat(arr) {
    arr = '[' + JSON.stringify(arr).replace(/\[|\]/g"") + ']';
    return JSON.parse(arr);
}

还有一种方法只能用于元素中没有对象的数组,因为toStringjoin在转换时会将对象转为[Object Object]形式。

toString/join +split的原理和上一个差不多,将数组转为string类型,然后通过split分割的形式去拿出元素。

function flat(arr) {
 return arr.toString().split(",").map(v => {
  return parseInt(v);
 })
}

3.扩展运算符+concat

ES6的扩展运算符...能通过迭代器拿出数组里的元素,concat在连接两个数组时也会拿出后一个数组里的元素。

[].concat(...[1,[2,[3]]])  //[1,2,[3]]

利用这个特性可以不用递归形式,如果元素是数组就用...展开,直至没有数组。

function flat(arr) {
 while(arr.some(item => Array.isArray(item))) { //some每一次都遍历整个arr比较耗时间,所以不是很推荐这个
  arr = [].concat(...arr);
    }
    return arr;
}

4.纯正递归

新开一个空间res进行递归。

function flat(arr) {
  let res = [];
  arr.map(v => {
    if(v instanceof Array) {
      res = res.concat(flat(v));
    }else{
      res.push(v);
    }
  });
  return res;
}