ES6中数组扁平化flat

512 阅读3分钟

var arr = [1, 2, [3, 4, [5, 6]]]

有这样一堆嵌套数组,或者又称为多维数组

es6中存在数组方法之flat,称为 数组扁平化,

flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。

var myArr = arr.flat(Infinity); //使用 Infinity 作为深度,展开任意深度的嵌套数组

即可输出 [1, 2, 3, 4, 5, 6]

当然 Infinity 也可替换为 具体数字,表示展开的层级,默认为 1

var myArr = arr.flat(); // [1, 2, 3, 4, [5, 6]]

var myArr = arr.flat(2); // [1, 2, 3, 4, 5, 6]

顺便延伸一个方法flatMap()

flatMap() 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。

它与 map 和 深度值1的 flat 几乎相同,但 flatMap 通常在合并成一种方法的效率稍微高一些。 这里我们拿map方法与flatMap方法做一个比较。

var arr1 = [1, 2, 3, 4];

arr1.map(x => [x * 2]); // [[2], [4], [6], [8]]

arr1.flatMap(x => [x * 2]); // [2, 4, 6, 8]// 只会将 flatMap 中的函数返回的数组 “压平” 一层

arr1.flatMap(x => [[x * 2]]);// [[2], [4], [6], [8]]

flat和flatMap方法目前还未在所有浏览器完全兼容。使用起来还需要看浏览器的兼容

www.caniuse.com/?search=fla…

记录一前端面试题

已知如下数组,编写一个程序将数组扁平化并除去其中重复部分数据,最终得

到一个升序且不重复的数组

var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10]

扁平化 arr.flat(Infinity)

扁平化去并除其中重复部分数据 new Set(arr.flat(Infinity))

最后升序 Array.from(new Set(arr.flat(Infinity))).sort((a, b) => { return a - b })

输出结果: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

2021年9月1日11:26:39

更新另一种方法 —— reduce

可多维数组转一维数组

还是这串 var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10]

 var newArr1 = function(arr) {

    return arr.reduce((pre, cur) => pre.concat(Array.isArray(cur) ? newArr1(cur) : cur), [])

}

这时候:newArr1 = [1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12, 13, 14, 10]
还没有去重,还没有排序,仅仅是 多维数组变成了一维数组
var newArr2 = Array.from(new Set(newArr1(arr))).sort((a, b) => { return a - b })

输出结果:newArr2  为 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

感觉还是冗余了。
不过reduce可以做很多事情。

var sum = arr.reduce(function(一个局部变量总和临时存储prev, 每一个元素cur, 元素当前index, 当前循环的数组arr) {
    return prev + cur;
},0) // 这里的0,相当于一个初始值,可以理解为 sum=0, 或者arrNew = []

// 举个栗子 -- 去重
// 如果是数组对象的话可以结合JSON.stringify(arr).includes(JSON.stringify({ label: '小a', value: 100 }))
const arr2 = [8, 8, 6, 5, 2, 2]
const newArr = arr2.reduce((pre, cur) => {
  if (!pre.includes(cur)) {
    return pre.concat(cur)
  } else {
    return pre
  }
}, []) // 最后 newArr = [8, 6, 5, 2]

// 举个栗子 -- 对象数组求和
const arr = [{ label: '小a', value: 100 }, { label: '小b', value: 55 }, { label: '小c', value: 86 }]
const result = arr.reduce((tmp, item, index) => {
  return tmp + item.value
}, 0)
console.log(result)// 求和 100+55+86=241

回到flat,扩展flatMap

console.log([1, 2, 3].flatMap((x) => [x * 2])) // 输出 [2, 4, 6]

console.log([1, [2, [3]]].flatMap((x) => [x * 2])) // 输出 [2, NaN]

从结果看来,flatMap只能压平一层数组,到了第二第三层那就不行

那只能 [1, [2, [3]]].flat(Infinity).flatMap((x) => [x * 2]) // 输出 [2, 4, 6]

所以,flatMap等于先执行了 flat(1),然后再map((x)=>{x * 2})

使用的时候可以看具体实际场景,取决于转换数组的维度