Javascript基础:老生常谈之数组扁平化

吐槽君 分类:javascript

首先是解释概念,什么是数组扁平化?

我们在平时开发过程中总可能会遇到数组嵌套数组,但是我们希望得到的数据是一个保持原有先后顺序的一维数组,所以数组扁平化这个想法应运而生。

// 这是一个多层嵌套的数组,假设有一个完美的数据扁平化方法_flat
const arr = [1, [3, 4], [7, [1, [9]]]]
console.log(_flat(arr)) // [1, 3, 4, 7, 1, 9]
 

接下来我们就来尝试使用各种方法来实现这个_flat。基本上是我能想到的最全的方法了。

  1. 普通递归

    这个思路其实比较容易理解,也是大家最容易想到的方法之一。首先我们去遍历一个数组,如果碰到有元素是数组,那么对该元素进行更深层的遍历。

    // 这里写的尽量避免使用了ES6
    function _flat(oriArr) {
    	let results = []
      for (let i = 0; i < oriArr.length; i++) {
        if (Object.prototype.toString.call(oriArr[i]) === '[object Array]') {
          results = results.concat(_flat(oriArr[i]))
        } else {
          results.push(oriArr[i])
        }
      }
      return results
    }
     
  2. 使用reduce函数

    这一种其实是对第一种方法的一个简化或美化,使用reduce去代替for循环同时又节约了一个新变量

    function _flat(oriArr) {
    	return oriArr.reduce(function (total, currentValue) {
    		return total.concat(Object.prototype.toString.call(currentValue) === '[object Array]' ? _flat(currentValue) : currentValue)
    	}, [])
    }
     
  3. ES6的扩展运算符
    function _flat(oriArr) {
    	while (oriArr.some(item => Array.isArray(item))) {
      	oriArr = [].concat(...oriArr)
      }
      return oriArr
    }
     

    看完上面的写法是不是突然感觉有一些疑惑和不自然?感觉扩展运算符好像跟自己理解地不太一样了,其实究其原因是因为对concat函数理解地不够透彻而已。用下面几个例子来说明

    // concat接收若干个参数,如果参数是非数组,那么会直接将它作为数组元素加入新数组
    // 如果参数是一个数组,那么会使用该数组的元素来作为来作为新数组的元素
    console.log([].concat(1, [2, 3])) // [1, 2, 3]
    console.log([].concat([1, 2], [3, 4])) // [1, 2, 3, 4]
    console.log([].concat(1, [2, [3, 4]])) // [1, 2, [3, 4]]
    console.log([].concat([1, [2, [3, 4]]])) // [1, [2, [3, 4]]]
    [].concat(...[1, [2, [3, 4]]]) === [].concat(1, [2, [3, 4]])
     
  4. 通过与字符串类型的相互转换
    function _flat(oriArr) {
    	// toString会将数组直接拉平成字符串,如 [1, [2, 3, [4, 5]]].toString() === '1,2,3,4,5'
    	// 然后通过split将其转换为数组
    	// 或者可以使用join代替toString,如oriArr.join(',').split(',')
    	return oriArr.toString().split(',')
    }
     
  5. ES6 flat

    对于这个方法其实很多人只知道不填的时候默认只拉平一层数组,填数组进去只拉平小于等于该数字的层级,但是其实它还可以用Infinity作为参数

    function _flat(oriArr) {
    	return oriArr.flat(Infinity)
    }
     
  6. 正则与JSON方法
    function _flat(oriArr) {
    	let str = JSON.stringify(oriArr)
    	str = str.replace(/(\[|\])/g, '')
    	str = '[' + str + ']'
    	return JSON.parse(str)
    }
     

    对正则不太理解的同学可以多看看语法,这里也推荐一个正则脑图的展示网站regexper.com/

总结

以上就是我能想到的6种数组扁平化的方法,其中4和6都进行了类型转换,那么这两种方法在特殊情况下势必会有一些问题,如数组中含有特殊符号,或者是数组中如果是数字,而最终返回的元素可能会变成字符串,都需要做一下特殊情况处理。

最后,望自己好好加油,不要再做咸鱼了~

作者:掘金-Javascript基础:老生常谈之数组扁平化

回复

我来回复
  • 暂无回复内容