数组扁平化

148 阅读4分钟

什么是扁平化呢???

  • 定义 : 扁平化就是将多维数组变成一维数组,不存在数组的嵌套
  • eg:已有多级嵌套数组 : [1, [2, [3, [4, 5]]], 6] 将其扁平化处理 输出: [1,2,3,4,5,6]

ES6 的 flat

 const arr = [1, [2, [3, [4, 5]]], 6] 
  function flat(params){
  return params.flat(Infiniity)
  } 
  console.log(flat(arr)) // 输出:        [1,2,3,4,5,6]

toString() 前提是都为数字 可以使用join(),toString()可以利用数组toString() 转为字符串

function flatten(params){
return params.toString().split(',').map(item =>parseFloat(item))

}

使用正则替换

看到嵌套的数组,如果在字符串的角度上看就是多了很多[ 和],如果把它们替换就可以实现简单的扁平化

function flatten (arr) {
console.log('JSON.stringify(arr)', typeof JSON.stringify(arr)) 
let str= JSON.stringify(arr).replace(/(\[|\])/g, ''); 
str = '[' + str + ']'; 
arr = JSON.parse(str); 
return arr } 
console.log(flatten(arr))
                      

循环递归

4.1 循环 + concat + push

  1. 不是数组,直接通过push添加到返回值数组
function flatten(arr) {
  let result = [];
  for (let i = 0; i < arr.length; i++) {
    if (Array.isArray(arr[i])) {
      result = result.concat(flatten(arr[i]));
    } else {
      result.push(arr[i])
    }
  }
  return result
}

console.log(flatten(arr));
或者使用`forEach` 立即执行函数

  // 递归版本的反嵌套
    function flatten(array) {
      var flattend = [];
      (function flat(array) {
        array.forEach(function(el) {
          if (Array.isArray(el)) flat(el);
          else flattend.push(el);
        });
      })(array);
      return flattend;
    }

4.2 增加参数控制扁平化深度

// forEach 遍历数组会自动跳过空元素
const eachFlat = (arr = [], depth = 1) => {
  const result = []; // 缓存递归结果
  // 开始递归
  (function flat(arr, depth) {
    // forEach 会自动去除数组空位
    arr.forEach((item) => {
      // 控制递归深度
      if (Array.isArray(item) && depth > 0) {
        // 递归数组
        flat(item, depth - 1)
      } else {
        // 缓存元素
        result.push(item)
      }
    })
  })(arr, depth)
  // 返回递归结果
  return result;
}

// for of 循环不能去除数组空位,需要手动去除
const forFlat = (arr = [], depth = 1) => {
  const result = [];
  (function flat(arr, depth) {
    for (let item of arr) {
      if (Array.isArray(item) && depth > 0) {
        flat(item, depth - 1)
      } else {
        // 去除空元素,添加非 undefined 元素
        item !== void 0 && result.push(item);
      }
    }
  })(arr, depth)
  return result;
}

4.3 巧用 reduce

reduce 方法为数组中的每个元素按序执行一个reducer函数,每一次运行 reducer 会将先前元素的计算结构作为参数传入,最后将其结果汇总为单个返回值

参数:

  1. callbackFn 一个 reducer 函数,包含四个参数:
  • previousVal :上一次调用callbackFn时的返回值,在第一次调用时,若指定了初始值initialValue,previousVal 的值就位 initialValue,否则初始值就是为数组的索引为 0 的元素
  • currentVal:数组中正在处理的元素,在第一次调用时,若指定了初始值,其值则为数组索引为 0 的元素 array[0],否则为 array[1]
  • currentIndex: 数组中正在处理的元素的索引,若指定了初始值 initialValue,则起始索引号为 0,否则从索引 1 起始
  • array : 用于遍历的数组
  1. initialValue(可选) : 作为第一次调用 callback 函数时参数 previousValue 的值

返回值: 使用 reducer 回调函数遍历整个数组后的结果

思路:

当我们使用 reduce 来解析第一层数组,可以得到:

const arr = [1, [[2, 3], 4],5]
const result = arr.reduce((acc, val) => acc.concat(val), []);
console.log(result);
// 输出: [1,[2,3],4,5]
复制代码

可以看出上面的代码可以扁平化一层数组,对于多层级嵌套的数组, 这个时候就需要使用递归的思想来解决问题了,再次遍历数组,发现数组元素任然是数组的时候,再次执行上面扁平化

手写方

const arr = [1, [[2, 3], 4],5] const flatten = (arr, deep = 1) => { if (deep <= 0) return arr; return arr.reduce((res, curr) => res.concat(Array.isArray(curr) ? flatten(curr, deep - 1) : curr), []) }

const flatten =(arr,deep=1){
  if(deep<0){
  return arr
  }
  return arr.reduce((res,eed)=>{ res.concat(Array.isArray(curr) ? flatten(curr, deep - 1) : curr), []) }})
}

4.4 使用 Generator 函数

"developer.mozilla.org/zh-CN/docs/… ES6 的实现,最大特点就是可以交出函数的执行权(即暂停执行)。

    它不同于普通函数,是可以暂停执行的,所以函数名之前要加星号,以示区别。
    整个 Generator 函数就是一个封装的异步任务,或者说是异步任务的容器。异步操作需要暂停的地方,
    都用 yield 语句注明。Generator 函数的执行方法如下。

    构造器生成新的生成器函数

    ```
    function* flatten(array) {
        for (const item of array) {
            if (Array.isArray(item)) {
                yield* flatten(item);
            } else {
                yield item;
            }
        }
    }

5. 使用堆栈 stack 避免递归

递归循环都可通过维护一个堆结构来解决

如果不使用递归数组来实现扁平化,可以使用堆栈来解决

深度的控制比较低效,因为需要检查每一个值的深度

**思路:**

1.  把数组通过一个栈来维护
2.  当栈不为空的时候循环执行处理
3.  pop()将栈尾出栈
4.  如果出栈的元素是数组,就将该元素解构后每一元素进行入栈操作
5.  出栈的元素不是数组就push进返回值res
6.  反转恢复原数组的顺序

function flatten(arr){
  const stack=[...arr];
  const res=[];
  while(stack.length){
  // 使用 pop 从 stack 中取出并移除值
  const next=stack.pop();
  if(Array.isArray(next)){
  // 使用 push 送回内层数组中的元素,不会改动原始输入             stack.push(...next);
  }else{
  res.push(next)
  
  }
  retuen res.reverse();
}

6.while 循环+ some方法

  方法测试数组中是不是至少有 1 个元素通过了被提供的函数测试。它返回的是一个 Boolean 类型的值。

 function flatten(arr){
  while(arr.some(item=>Array.isArray(item))){
    arr = [].concat(...arr)                        
  }
 
  return arr
 }

总结

实现数组扁平化的方法有很多, 评分也每个人有各自的看法, 欢迎大家在评论区留下你自己对每个实现方式的评分,一起学习交流哦!