JS專題之陣列展開

種瓜南山下發表於2019-02-16

前言

首先什麼是陣列展開?
假如現在有這樣一個需求:將後臺的一個多重 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"];

複製程式碼

總結

陣列扁平化其實就是利用元素迭代 + 元素拼接(疊加)+ 遞迴呼叫來對陣列進行處理,達到將多層陣列轉換為單層陣列的過程。 歡迎關注我的個人公眾號“謝南波”,專注分享原創文章。

JS專題之陣列展開

掘金專欄 JavaScript 系列文章

  1. JavaScript之變數及作用域
  2. JavaScript之宣告提升
  3. JavaScript之執行上下文
  4. JavaScript之變數物件
  5. JavaScript之原型與原型鏈
  6. JavaScript之作用域鏈
  7. JavaScript之閉包
  8. JavaScript之this
  9. JavaScript之arguments
  10. JavaScript之按值傳遞
  11. JavaScript之例題中徹底理解this
  12. JavaScript專題之模擬實現call和apply
  13. JavaScript專題之模擬實現bind
  14. JavaScript專題之模擬實現new
  15. JS專題之事件模型
  16. JS專題之事件迴圈
  17. JS專題之去抖函式
  18. JS專題之節流函式
  19. JS專題之函式柯里化
  20. JS專題之陣列去重
  21. JS專題之深淺拷貝

相關文章