我們現在來說說怎么寫一下數組扁平化flat(),怎么樣?簡單說題目就是數組扁平化(也可以叫做手動封裝flat()方法),如何寫好那?
按照不同的星級進行打分: 五星打分制
滿分: ?????
題目實現扁平化的方法 封裝 flatten
題目描述:
有多級嵌套數組 :[1, [2, [3, [4, 5]]], 6]將其扁平化處理 輸出:[1,2,3,4,5,6]
什么是扁平化
定義 : 扁平化就是將多維數組變成一維數組,不存在數組的嵌套
1. ES6 flat
flat(depth)方法會按照一個可指定的深度遞歸遍歷數組,并將所有元素與遍歷到的子數組中的元素合并為一個新數組返回。
參數:
depth(可選) 指定要提取嵌套數組的結構深度,默認值為 1
返回值:
返回一個新數組,包含數組與提取嵌套數組的所有元素的新數組
使用Infinity,可展開任意深度的嵌套數組
封裝思路: 使用 es6 自帶 API 處理
const arr = [1, [2, [3, [4, 5]]], 6] function flatten(params) { return params.flat(Infinity) } console.log(flatten(arr)); // 輸出: [1,2,3,4,5,6]
得分 :?
直接使用自帶的方法可以很快的實現,但這個不是合適的!
2. toString
如果數組的項全為數字,可以使用join(),toString()可以利用數組toString() 轉為字符串
function flatten(arr) { return arr.toString().split(',').map(item =>parseFloat(item)) } console.log(flatten(arr)); // 輸出:[ 1, 2, 3, 4, 5, 6 ]
得分 :? (并不是要考你的數組的方法調用)
3. 使用正則替換
看到嵌套的數組,如果在字符串的角度上看就是多了很多[和],如果把它們替換就可以實現簡單的扁平化
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. 循環遞歸
4.1 循環 + concat + push
當只有一層嵌套數組使用push的方式扁平化
[1, [2, 3,4,5,6]]
let result = []; for (let i = 0; i < arr2.length; i++) { result = result.concat((arr2[i])); } console.log(result); [ 1, 2, 3, 4, 5, 6 ]
如果有多層嵌套的數組就需要使用遞歸的思想:
思路
循環判斷數組的每一項是否是數組: Array.isArray(arr[i])
是數組就遞歸調用上面的扁平化一層的代碼 result = result.concat(flatten(arr[i]));
不是數組,直接通過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; }
當然循環可以更改成forEach循環,for of ...等其他循環,簡單的循環遞歸就能夠一樣的解決啦~
得分:??? (能夠使用遞歸寫出數組扁平化,缺少控制層級關系)
4.2 增加參數控制扁平化深度
這個可以理解為手寫flat()方法啦~
// 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 會將先前元素的計算結構作為參數傳入,最后將其結果匯總為單個返回值
參數:
callbackFn一個 reducer 函數,包含四個參數:
previousVal :上一次調用callbackFn時的返回值,在第一次調用時,若指定了初始值initialValue,previousVal 的值就位 initialValue,否則初始值就是為數組的索引為 0 的元素
currentVal:數組中正在處理的元素,在第一次調用時,若指定了初始值,其值則為數組索引為 0 的元素 array[0],否則為 array[1]
currentIndex: 數組中正在處理的元素的索引,若指定了初始值 initialValue,則起始索引號為 0,否則從索引 1 起始
array : 用于遍歷的數組
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] function flatten (arr,deep=1) { return arr.reduce((acc,val) => acc.concat(Array.isArray(val)? flatten(val,deep-1):val),[]) } console.log(arr, Infinity); // 輸出:[ 1, 2, 3, 4, 5, 6 ]
得分:???? (能夠使用遞歸寫出數組扁平化,巧用reduce方法可加分)
4.4 使用 Generator 函數
GeneratorFunction是協程在 ES6 的實現,最大特點就是可以交出函數的執行權(即暫停執行)。
它不同于普通函數,是可以暫停執行的,所以函數名之前要加星號,以示區別。
整個 Generator 函數就是一個封裝的異步任務,或者說是異步任務的容器。異步操作需要暫停的地方,都用 yield 語句注明。Generator 函數的執行方法如下。
構造器生成新的生成器函數
function* flatten(array) { for (const item of array) { if (Array.isArray(item)) { yield* flatten(item); } else { yield item; } } }
得分:??? (使用Generator 函數 進行遞歸)
5. 使用堆棧 stack 避免遞歸
遞歸循環都可通過維護一個堆結構來解決
如果不使用遞歸數組來實現扁平化,可以使用堆棧來解決
深度的控制比較低效,因為需要檢查每一個值的深度
思路:
把數組通過一個棧來維護
當棧不為空的時候循環執行處理
pop()將棧尾出棧
如果出棧的元素是數組,就將該元素解構后每一元素進行入棧操作
出棧的元素不是數組就push進返回值res
反轉恢復原數組的順序
var arr1 = [1,2,3,[1,2,3,4, [2,3,4]]]; 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); } } // 反轉恢復原數組的順序 return res.reverse(); } flatten(arr1);// [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]
得分:???? (使用數據結構棧的特性取代遞歸操作,減少時間復雜度)
6.while 循環+ some方法
some:方法測試數組中是不是至少有 1 個元素通過了被提供的函數測試。它返回的是一個 Boolean 類型的值。
思路
通過some來判斷數組中是否用數組,通過while不斷循環執行判斷, 如果是數組的話可以使用 拓展運算符... ... 每次只能展開最外層的數組,加上contact來減少嵌套層數,
function flatten(arr) { while (arr.some(item=> Array.isArray(item))) { console.log(...arr) arr = [].concat(...arr) console.log(arr) } return arr } console.log(flatten(arr));
得分:???? (使用while循環取消遞歸操作, 巧用some操作進行判斷)
全文內容已講述完畢,歡迎大家后續關注更多精彩內容。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/128174.html
摘要:協議主要是通過請求頭當中的一些字段來和服務器進行通信,從而采用不同的緩存策略。會緩存所有的結構,但是問題在于,一些頁面開始時進行的上報或者請求可能會被影響。 1.如何用一個div實現下圖 showImg(https://segmentfault.com/img/bVbm8Rf?w=133&h=134); css #demo{ width:120px; h...
摘要:協議主要是通過請求頭當中的一些字段來和服務器進行通信,從而采用不同的緩存策略。會緩存所有的結構,但是問題在于,一些頁面開始時進行的上報或者請求可能會被影響。 1.如何用一個div實現下圖 showImg(https://segmentfault.com/img/bVbm8Rf?w=133&h=134); css #demo{ width:120px; h...
摘要:序列文章面試之函數面試之對象前言本文主要從應用來講數組的一些騷操作如一行代碼扁平化維數組數組去重求數組最大值數組求和排序對象和數組的轉化等上面這些應用場景你可以用一行代碼實現扁平化維數組終極篇是扁平數組的表示維度值為時維度為無限大開始篇實質 showImg(https://segmentfault.com/img/bVbpRMS?w=1858&h=1286); 序列文章 JS面試之函數...
閱讀 547·2023-03-27 18:33
閱讀 732·2023-03-26 17:27
閱讀 630·2023-03-26 17:14
閱讀 591·2023-03-17 21:13
閱讀 521·2023-03-17 08:28
閱讀 1801·2023-02-27 22:32
閱讀 1292·2023-02-27 22:27
閱讀 2178·2023-01-20 08:28