前言
首先什麼是陣列展開?
假如現在有這樣一個需求:將後臺的一個多重 List 資料,展開成一個 List 後,並去重後排序;
["a", "b", ["c", "d"], [["d"],"e"], "f"] => ["a", "b", "c", "d", "e"];
複製程式碼
陣列去重我們前面在《JS專題之陣列去重》已經講過了,那麼前一步的多重陣列展開成單層陣列,該如何處理呢?
這就來到我們所要探討的陣列展開了。
根據需求的特點,陣列展開需要進行迭代和遞迴。
回答文章開頭的問題:
將多重陣列轉化成單層陣列的過程就是陣列展開,也叫作陣列扁平化(flatten)
一、迴圈加遞迴
最簡單的思路:迴圈中判斷,如果子元素是陣列則遞迴。
function flatten(origin) {
var result = [];
for(var i = 0; i< origin.length; i++) {
var item = origin[i];
if(Array.isArray(item)) {
result = result.concat(flatten(item))
} else {
result.push(item);
}
}
return result;
}
var arr = ["a", "b", ["c", "d"], [["d"],"e"], "f"];
flatten(arr); // ["a", "b", "c", "d", "d", "e", "f"]
複製程式碼
二、toString()
陣列的原型物件上有一個方法,toString, 它能把陣列的所以元素轉化成用逗號隔開的字串。
var arr = [1, [2, 3, [4]], "a", "b", ["c", "d"], [["d"],"e"], "f"];
arr.toString() // "1,2,3,4,a,b,c,d,d,e,f"
// 所以,利用 split 先把字串轉化為單層陣列,再進行處理。
const flatten = (origin) => origin.toString().split(','); // ["1", "2", "3", "4", "a", "b", "c", "d", "d", "e", "f"]
複製程式碼
由於 toString 轉化為字串的時候,不會區分字串和數字型別,在進行區分資料型別的時候要注意。
三、split
上面的方法,我們用 toString() 將陣列轉化為字串,那麼我們也可以用 split 來做:
var arr = [1, [2, 3, [4]], "a", "b", ["c", "d"], [["d"],"e"], "f"];
function flatten(arr) {
return arr.join(',').split(',');
}
console.log(flatten(arr))。 // ["1", "2", "3", "4", "a", "b", "c", "d", "d", "e", "f"]
複製程式碼
同樣,這種字串和陣列互轉的過程,不適合多種資料型別同時處理。
四、reduce
我們注意到其實陣列扁平化其實就是“迭代 + 拼接(累加) + 遞迴”的過程,陣列 reduce 方法既可以迭代又可以累加,適合做陣列扁平化。
function flatten(origin){
return origin.reduce(function(init, item){
return init.concat(Array.isArray(item) ? flatten(item) : item)
}, [])
}
var arr = [1, [2, 3, [4]], "a", "b", ["c", "d"], [["d"],"e"], "f"];
console.log(flatten(arr)) // [1, 2, 3, 4, "a", "b", "c", "d", "d", "e", "f"]
複製程式碼
五、some + concat
some 會遍歷陣列的每一個元素,判斷是否有元素都滿足條件,最後返回布林值。some 一旦返回真值後,其後的元素就不會繼續監測。
function flatten(origin) {
while (origin.some(item => Array.isArray(item))){
origin = [].concat.apply([], origin);
}
return origin;
}
var arr = [1, [2, 3, [4]], "a", "b", ["c", "d"], [["d"],"e"], "f"];
console.log(flatten(arr)) // [1, 2, 3, 4, "a", "b", "c", "d", "d", "e", "f"]
複製程式碼
六、some + 擴充套件運算子
ES6 擴充套件運算子...
可以將兩重陣列轉換為單層陣列:
[].concat(...[1, [2, 3, [4]], "a", "b", ["c", "d"], [["d"],"e"], "f"]); // [1, 2, 3, Array(1), "a", "b", "c", "d", Array(1), "e", "f"]
// 利用 some 方法,我們可以實現多重轉換為單層:
function flatten(origin) { while(origin.some(item=> Array.isArray(item))) {
origin = [].concat(origin);
} return origin;
}
var arr = [1, [2, 3, [4]], "a", "b", ["c", "d"], [["d"],"e"], "f"];
console.log(flatten(arr)) // [1, 2, 3, 4, "a", "b", "c", "d", "d", "e", "f"]
複製程式碼
七、原生 flat
JS Array 物件提供了原生的可以實現扁平化的函式flat:詳細說明見 MDN
var arr = [1, [2, 3, [4]], "a", "b", ["c", "d"], [["d"],"e"], "f"];
// 2 表示深度
arr.flat(2) // [1, 2, 3, 4, "a", "b", "c", "d", "d", "e", "f"];
複製程式碼
總結
陣列扁平化其實就是利用元素迭代 + 元素拼接(疊加)+ 遞迴呼叫來對陣列進行處理,達到將多層陣列轉換為單層陣列的過程。 歡迎關注我的個人公眾號“謝南波”,專注分享原創文章。
掘金專欄 JavaScript 系列文章
- JavaScript之變數及作用域
- JavaScript之宣告提升
- JavaScript之執行上下文
- JavaScript之變數物件
- JavaScript之原型與原型鏈
- JavaScript之作用域鏈
- JavaScript之閉包
- JavaScript之this
- JavaScript之arguments
- JavaScript之按值傳遞
- JavaScript之例題中徹底理解this
- JavaScript專題之模擬實現call和apply
- JavaScript專題之模擬實現bind
- JavaScript專題之模擬實現new
- JS專題之事件模型
- JS專題之事件迴圈
- JS專題之去抖函式
- JS專題之節流函式
- JS專題之函式柯里化
- JS專題之陣列去重
- JS專題之深淺拷貝