数组扁平化(一层、全部展开、指定深度)
参考文章:数组拍平连环问 - 只研究到第二问 reduce,没有再深入,一共七问
题目:
如何实现 flat
方法?多维数组=>一维数组
方法总结:
-
展开一层:
1、concat直接传一组参数:『
[].concat(...arr)
』2、concat通过apply/call传参数:
[].concat.apply([], arr)
/[].concat.call([], ...arr)
3、flat:
arr.flat()
-
全部展开:
1、flat:
arr.flat(Infinity)
2、toString 法:
arr.toString().split(',')
,toString 转成字符串会将数组全部打平3、reduce法递归: concat的参数为数组/值:
function flatFun(arr){ return arr.reduce((pre, cur) => pre.concat(Array.isArray(cur) ? flatFun(cur) : cur), []) }
常见 :遍历forEach组装res - 本质就是 reduce
-
根据指定深度扁平数组 『deep-1』『deep>1』
function flattenByDeep(arr, deep = 1) { return arr.reduce((pre, cur) => pre.concat(Array.isArray(cur) && deep > 1 ? flattenByDeep(cur, deep - 1) : cur) , []) }
详细解答:
-
方法一: 直接调用
Array
的flat
方法 -arr = arrays.flat(Infinity);
作用是将嵌套的数组“拉平”,变成一维的数组。返回一个新数组,对原数据没有影响。
- 不传参数时,默认“拉平”一层
- 传入一个整数参数,整数即“拉平”的层数
Infinity
关键字作为参数时,无论多少层嵌套,都会转为一维数组- 传入
<=0
的整数将返回原数组,不“拉平” - 如果原数组有空位,
flat()
方法会跳过空位
const animals = ["🐷", ["🐶", "🐶"], ["🐶", ["🐑", ["🐲"]], "🐷"]]; // 不传参数时,默认“拉平”一层 animals.flat(); // ["🐷", "🐶", "🐶", "🐶", ["🐑", ["🐲"]], "🐷"] // 传入一个整数参数,整数即“拉平”的层数 animals.flat(2); // ["🐷", "🐶", "🐶", "🐶", "🐑", ["🐲"], "🐷"] // Infinity 关键字作为参数时,无论多少层嵌套,都会转为一维数组 animals.flat(Infinity); // ["🐷", "🐶", "🐶", "🐶", "🐑", "🐲", "🐷"] // 传入 <=0 的整数将返回原数组,不“拉平” animals.flat(0); animals.flat(-10); // ["🐷", ["🐶", "🐶"], ["🐶", ["🐑", ["🐲"]], "🐷"]] // 如果原数组有空位,flat()方法会跳过空位 ["🐷", "🐶", "🐂", "🐎",,].flat(); // ["🐷", "🐶", "🐂", "🐎"]
-
方法二:
自己实现的核心思路:在数组中找到是数组类型的元素,然后将他们展开
-
第一个要解决的就是遍历数组的每一个元素;
for 循环
、for...of
、for...in
、forEach()
、entries()
、keys()
、values()
、reduce()
、map()
// entries()- 返回可枚举【属性的键值对】数组 for (let [index, value] of arr.entries()) {console.log(index, value)} // keys() - 返回可枚举【属性】组成的数组 for (let index of arr.keys()) {console.log(index)} // values() - 返回可枚举【属性值】的对象 for (let value of arr.values()) {console.log(value)} // reduce() - 详细见同目录下 reduce 博文 arr.reduce((pre, cur) => {console.log(pre, cur); return pre;}, []); // map() - 一个由原数组每个元素执行回调函数的结果组成的新数组 arr.map(value => console.log(value));
-
第二个要解决的就是判断元素是否是数组; - 详细查看单独博客
instanceof
、constructor
(可被改写,不准确)、Object.prototype.toString
(可被改写,不准确)、isArray
let arr = [1, 2, 3]; arr instanceof Array; // true arr.constructor === Array; // true Object.prototype.toString.call(arr) === '[object Array]'; // true Array.isArray(arr);// true
-
第三个要解决的就是将数组的元素 展开
- 展开一层
第1⃣️种:
...
扩展运算符 +concat
【注意】:扩展运算符(…)内部使用
for…of
循环const animals = ["🐷", ["🐶", "🐶"], ["🐶", ["🐑", ["🐲"]], "🐷"]]; arrays = [].concat(...animals);// ["🐷", "🐶", "🐶", "🐶", Array(2), "🐷"]
第2⃣️种:
apply
+concat
apply
在绑定作用域时,会将传入的 数组元素作为单独的参数 的传入到要执行的函数中arrays = [].concat.apply([], animals); // 实际逐一执行类似于 [].concat("🐷").concat(["🐶", "🐶"]).concat(["🐶", ["🐑", ["🐲"]]]).concat("🐷");
- 全部展开
第3⃣️种:
toString
+split
arr2.toString().split(','); // toString() 方法会把数组打平 - "🐷,🐶,🐶,🐶,🐑,🐲,🐷"
扩展:通过 正则 +
split
let str = JSON.stringify(arrays); // 处理成字符串 // 将全局所有 []"" 替换成空 arr1 = str.replace(/(\]|\[|\"|\")/g, '').split(',');
let str = JSON.stringify(arrays); // 处理成字符串 str = str.replace(/(\]|\[|\"|\")/g, ''); str = '[' + str + ']'; // 通过 JSON.parse 将字符串转换成数组 ary = JSON.parse(str);
第4⃣️种:递归
找到所有数组元素,递归,直到找到底层非数组元素,返回抛出
function flatFun(arr) { let res = []; arr.forEach(item => { if (Array.isArray(item)) { res = res.concat(flatFun(item)); } else { res.push(item); } // 上面的 if 逻辑可以利用concat特性,简写成 // res = res.concat(Array.isArray(item) ? flatFun(item) : item) }); return res; } // 另一种写法 - 每次非数组都要执行一次递归,消耗大,不采用 function flatFun2(target) { if (!Array.isArray(target)) { return [target]; // 同时在这边返回长度为1的数组类型 } let res = []; target.forEach(it => res.push(...flatFun2(it))); // 这边注意一定要加 ... 因为返回的res都是数组 return res; }
第5⃣️种:
reduce
var flatFun = (arrays) => { return arrays.reduce((pre, cur) => { // 写法一: return pre.concat(Array.isArray(cur) ? flatFun(cur) : cur); // 写法二: // return (Array.isArray(cur) ? pre.concat(flatFun(cur)) : pre.concat(cur)); },[]) }
-
-
补充情况:根据指定深度扁平数组
-
第⑥种
function flattenByDeep(arr, deep = 1) { return arr.reduce((pre, cur) => Array.isArray(cur) && deep > 1 ? pre.concat(flattenByDeep(cur, deep - 1)) : pre.concat(cur) // 可以简写成 // pre.concat(Array.isArray(cur) && deep > 1 ? flattenByDeep(cur, deep - 1) : cur) , [] ) }
-