likes
comments
collection
share

数组扁平化,你会几种

作者站长头像
站长
· 阅读数 16

前言

数组扁平化,作为一个常见的面试题,经常会被面试官用来考验我们对于 JS 的掌握水平

数组的扁平化是指将多层嵌套的数组结构(嵌套可以是任何层数)转换为只有一层的数组。在 JavaScript 中,有多种方法可以实现数组扁平化。

本文将介绍六种常见的实现方法,并对它们进行总结和比较。

实现

普通递归实现

使用递归方式遍历数组中的每个元素,如果当前元素是数组,则递归调用该函数将其展平,否则将当前元素添加到结果数组中。最终返回展平后的结果数组

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
}
let arr = [1, 2, [3, 4], [5, [6, 7]]]
console.log(flatten(arr))// [1, 2, 3, 4, 5, 6, 7]

在这个例子中,flatten 函数接受一个数组参数 arr,并返回一个扁平化后的数组。在遍历数组元素时,如果当前元素是数组,则递归调用 flatten 函数将其展开,并使用 Array.prototype.concat 方法将展开后的数组与结果数组合并;否则将当前元素添加到结果数组中。最终返回结果数组。

用 reduce 方法迭代

从上面的普通递归中可以看出,其实就是对数组的每一项进行处理,我们这里用到reduce函数来实现数组的拼接,从而简化第一种代码

函数接受一个数组 arr 作为参数,并使用 reduce() 方法对数组进行迭代。reduce() 方法接受一个回调函数和一个初始值(这里是空数组 [])作为参数。

回调函数中的逻辑如下:

  1. 对于每个数组元素 cur,检查它是否是数组,使用 Array.isArray() 方法进行判断。
  2. 如果 cur 是数组,那么递归调用 flatten(cur),继续展开嵌套的数组。
  3. 如果 cur 不是数组,表示是一个非嵌套的元素,直接将其添加到结果数组中。
  4. 使用 concat() 方法将展开后的数组或非嵌套元素连接到结果数组 pre 中。
function flatten(arr) {
    return arr.reduce((pre, cur) => {
        return pre.concat(Array.isArray(cur) ? flatten(cur) : cur);
    }, []);
}
let arr = [1, 2, [3, 4], [5, [6, 7]]]
console.log(flatten(arr))// [1, 2, 3, 4, 5, 6, 7]
    

扩展运算符实现

使用了循环结构和拓展运算符 ... 来遍历数组中的每个元素,如果当前元素是数组,则使用 concat 方法将其展开并将结果赋值给原数组,直到数组中不再包含嵌套数组为止。

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

let arr = [1, 2, [3, 4], [5, [6, 7]]]
console.log(flatten(arr))// [1, 2, 3, 4, 5, 6, 7]
    

在这个示例中,flatten 函数接受一个数组参数 arr,并不返回任何值。在循环结构中,使用 some 方法判断数组中是否还存在嵌套数组,如果存在,则使用 concat 方法将嵌套数组展开,并使用拓展运算符 ... 将展开后的数组合并。这个过程会不断重复,直到数组中不再包含嵌套数组。

concat 方法创建一个新数组。该数组将首先由调用它的对象中的元素填充。然后,对于每个参数,它的值将被连接到数组中——对于普通对象或基元,参数本身将成为最终数组的一个元素;对于属性Symbol.isConcatSpreadable设置为真的数组或类数组对象,参数的每个元素都将是独立地添加到最终数组中详情可查看MDN concat

简单来说就是,如果是普通对象或者基础数据类型,就直接添加进新数组;如果是数组或者类数组对象,那就是将数组和类数组对象的元素添加进新数组

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

在计算机程序设计中,基元(primitive)是指最基本的数据类型,也称为原始数据类型(primitive data type)。在这里自然指的是数字类型,字符串类型,布尔类型等基础数据类型

前三种实现数组扁平化的方式都是最基本的思路,都是通过最普通递归思路衍生出来的方法

ES6的flat

直接调用 ES6 的 flat ,可以直接实现数组扁平化

array.flat([depth])
  • depth(可选):指定要递归扁平化的嵌套层数,默认为 1。如果传递一个大于 0 的整数,表示递归扁平化的层数;如果传递 Infinity,则会完全扁平化所有嵌套的子数组
let arr = [1, 2, [3, 4], [5, [6, 7]]]
console.log(arr.flat(Infinity))// [1, 2, 3, 4, 5, 6, 7]

flat 方法的内部实现是使用迭代的方式来展平数组,其时间复杂度为 O(n),空间复杂度为 O(n)。

在执行 flat 方法时,它会遍历原数组中的每个元素,并判断该元素是否为数组。如果是数组,则将其中的元素> 追加到展平后的结果数组中;否则直接将该元素追加到结果数组中。这样,就可以将嵌套数组展平成一个一维数组。

在展平的过程中,flat 方法会创建一个新的数组来存储展平后的结果。因此,展平后的结果数组的长度和原数组中所有元素的数量一样。这就是空间复杂度为 O(n) 的原因。

以上四个flatten方法都是相同输出

const arr1 = [1, [2, [3, [4, 5]]], {obj: 1}, function aaa() {}, new RegExp(), new Date(), null, undefined, '2', false,  ];

数组扁平化,你会几种

toString和split共同处理


function flatten(arr) {
    return arr.toString().split(',')
}

var arr1 = [1, [2, [3, [4, 5]]], {obj: 1}, function aaa() {}, new RegExp(), new Date(), null, undefined, '2', false,  ];



arr.toString().split(',') 的作用是将数组 arr 转换为一个字符串,然后使用逗号分隔符将字符串拆分为一个字符串数组。具体来说,它使用了 Array.prototype.toString() 方法将数组转换为一个字符串,然后使用 String.prototype.split() 方法将字符串按照逗号分隔符拆分为一个字符串数组。这个方法常用于将数组展开为一组逗号分隔的值,或者将一个字符串按照逗号分隔符拆分为一个字符串数组。

这种方法的优点是代码简洁,易于理解和实现。但缺点也显而易见

  1. 不能处理数组中包含逗号的情况。因为逗号会被误认为是分隔符,导致数组元素无法正确地转换为字符串
  2. 不能处理数组中包含 undefined、null、NaN 等特殊值的情况,因为这些值在转换为字符串时会变成空字符串或字符串

数组扁平化,你会几种

6. 正则和 JSON 方法结合

通过将数组转换为字符串,去除其中的方括号,然后重新构造为一个数组字符串,并最后将其解析为数组。

由于使用到了 JSON.stringify() 方法,所以无法对 函数undefined 、symbolDate引用类型 等类型正确转换

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

const arr1 = [1, [2, [3, [4, 5]]], {obj: 1}, function aaa() {}, new RegExp(), new Date(), null, undefined, '2', false, ];
console.log(flatten(arr1))

数组扁平化,你会几种

总结

数组扁平化是一项常见的任务,可以通过多种方法实现。上面介绍了六种实现数组扁平化的常见方法,也说明了各自的优缺点,希望大家能够更好的了解Javascript和面试的时候能够用得上

至于开发过程中,还是用现成的就好,毕竟开发工作中效率第一嘛

最后,祝大家变得更强!