前端百題——居然有五種方式實現flat方法

1 背景

不知道老鐵們有沒有遇到過一道面試題:如何將一個多維數組展開成一個一維數組?當時我遇到的時候還不瞭解flat這個神奇的方法,用了最傳統的解決方法進行解決。javascript

const flatten = arr => arr.toString().split(',').map(item => +item);

const arr = [1, 2, [3, 4, [5, 6]]];
console.log(flatten(arr)); // [ 1, 2, 3, 4, 5, 6 ]
複製代碼

上述方法是否是很神奇,會將多層級的數組展開成爲一個層級,可是該方式其實存在很大問題的,下面讓咱們一塊兒看看這些問題。html

  1. 無論多少層級都會展開爲一個層級;
  2. 處理後的結果其實都是字符串,須要後續再轉換爲原來的類型。

正是基於這個契機,發現了ES6新增了flat函數,這個函數天生就是爲數據扁平化處理而生的。java

2 flat基礎

flat() 方法會按照一個可指定的深度遞歸遍歷數組,並將全部元素與遍歷到的子數組中的元素合併爲一個新數組返回。git

  1. flat方法的用法以下所示:
const newArray = arr.flat([depth])
複製代碼
  1. 小試牛刀
const arr = [1, 2, [3, 4, [5, 6]]];
console.log(arr.flat(1)); // [ 1, 2, 3, 4, [ 5, 6 ] ]
console.log(arr.flat(2)); // [ 1, 2, 3, 4, 5, 6 ]
複製代碼

3 實現

flat這麼香,那麼咱們是否能夠本身實現一個呢?實現該方法的方式有不少,下面就讓咱們一塊兒看看這五種方式。(注:這五種方式試MDN上給出的替代方案)github

3.1 使用reduce和concat

該方式實現起來雖然很簡單,可是存在一個很大的缺陷:只能展開一層,對於多層的狀況將無能爲力。其思想總結起來爲如下兩個步驟:面試

  1. 利用reduce函數去依次處理每一個數組中的元素;
  2. 利用concat將當前的數組元素(值或子數組)添加到結果數組中。
// 使用reduce和concat
Array.prototype.flat1 = function () {
    return this.reduce((acc, val) => acc.concat(val), []);
}
複製代碼

3.2 使用reduce + concat + isArray + recursivity

該方式已經具有展開多層的能力了,其實現思想可總結爲如下幾點:數組

  1. 利用reduce函數去依次處理每一個數組中的元素;
  2. 利用concat將當前元素添加到結果數組中;
  3. 利用isArray判斷當前數組中的元素是否是一個數組;
  4. 利用遞歸思想展開多層級的數組。
// 使用reduce + concat + isArray +recursivity
Array.prototype.flat2 = function (deep = 1) {
    const flatDeep = (arr, deep = 1) => {
        return deep > 0 ? arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? flatDeep(val, deep - 1) : val), []) : arr.slice();
    }

    return flatDeep(this, deep);
}
複製代碼

3.3 使用forEach + concat + isArray +recursivity

該方式與上述方式很相似,可以設定層級展開,只是遍歷數組由reduce轉換爲forEach。函數

// 使用forEach + concat + isArray +recursivity
// forEach 遍歷數組會自動跳過空元素
Array.prototype.flat3 = function (deep = 1) {
    const result = [];
    (function flat(arr, deep) {
        arr.forEach((item) => {
            if (Array.isArray(item) && deep > 0) {
                flat(item, deep - 1);
            } else {
                result.push(item);
            }
        })
    })(this, deep);

    return result;
}
複製代碼

3.4 使用for of + concat + isArray +recursivity

該方式與上述方式很相似,可以設定層級展開,只是遍歷數組利用了for of方法post

// 使用for of + concat + isArray +recursivity
// for of 遍歷數組會自動跳過空元素
Array.prototype.flat4 = function (deep = 1) {
    const result = [];
    (function flat(arr, deep) {
        for(let item of arr) {
            if (Array.isArray(item) && deep > 0) {
                flat(item, deep - 1);
            } else {
                // 去除空元素,由於void 表達式返回的都是undefined,不適用undefined是由於undefined在局部變量會被重寫
                item !== void 0 && result.push(item);
            }
        }
    })(this, deep);

    return result;
}
複製代碼

3.5 使用堆棧stack

該方式主要利用堆棧的思想,將一個多層數組所有展開爲一層。其思想可總結爲如下幾個步驟:this

  1. 將要處理的數組放到一個棧中處理;
  2. 從棧頂取出元素,判斷該元素類型,若爲數組,則將該數組展開再放回棧頂;若爲普通元素則將其放到結果中;
  3. 循環遍歷,至到棧爲空。
// 使用堆棧stack
Array.prototype.flat5 = function() {
    const stack = [...this];
    const result = [];
    while (stack.length > 0) {
        const next = stack.pop();
        if (Array.isArray(next)) {
            stack.push(...next);
        } else {
            result.push(next);
        }
    }

    // 反轉恢復原來順序
    return result.reverse();
}
複製代碼

1.若是以爲這篇文章還不錯,來個分享、點贊吧,讓更多的人也看到

若是你以爲這篇文章對你有點用的話,麻煩請給咱們的開源項目點點star:        http://github.crmeb.net/u/defu         不勝感激 !
來自 「開源世界 」 ,連接:      https://ym.baisou.ltd/post/737.html ,如需轉載,請註明出處,不然將追究法律責任。 ​​​​​​
相關文章
相關標籤/搜索