清明節,這幾天放假閑來無事,好好研究一下基礎知識,今天看看數組扁平化該怎么處理:
先來看數組扁平化是什么:
var arr = [1,2,3,4,[5,6,[7,8]],true] => [1,2,3,4,5,6,7,8,true]
就是把二維或者多維數組,轉成一維數組。
1、我想大部分同學會和一樣,首先想到的肯定是遍歷數組,如果某一項是基本數據類型,直接push到新數組,如果某一項是數組,則直接將這一項concat到新的數組上,當然如果是多維數組,還得用上遞歸的方法,繼續往下層尋找,上代碼:
function flatten(arr) { var result = [] for (var i = 0; i < arr.length; i++) { console.log(arr[i]) if (Array.isArray(arr[i])) { result = result.concat(flatten(arr[i])) // 如果是數組,則直接拼接到新數組 } else { result.push(arr[i]) // 基本類型數據,直接push到新數組 } } return result }
console.log(arr, flatten(arr)) // [1, 2, 3, 4, Array(3), true] [1, 2, 3, 4, 5, 6, 7, 8, true]
我們看看結果,已經得到我們想要的結果了,且原數組沒變化。
2、第二種方法:使用 數組的reduce(fn(), init, index, arr)+concat()方法
a.遍歷每一項,並按fn()中規則處理每一項: 如果是基本類型,暴力concat到要返回的數組中,如果是數組則拼接到返回的數組上,如果是多維數組,遞歸調用;
b.init是要返回結果的初始值;
c第三和四參數可省略。
function flatten(arr) { return arr.reduce((result, item) => { return result.concat(Array.isArray(item) ? flatten(item) : item) }, []) }
console.log(arr, flatten(arr)) // [1, 2, 3, 4, Array(3), true] [1, 2, 3, 4, 5, 6, 7, 8, true]
我們看看結果,也得到我們想要的結果了,且原數組沒變化。
3、第三種方法: 使用while循環some條件和apply特性,我們知道apply(obj, [ ])
a.第一個參數,是要調用已存在方法的對象,例如c.apply(d, []) ,d就繼承了c的特性,這個參數和這篇文章沒有太大關系,可以先不理解;
b.第二個參數是指的,要處理的數據,且一定是一個值,可以是數組或其他值,但必須是一個,如果是一個數組,那么會一次處理數組中的元素。好,這里就是利用這個特性,一次處理數組中的每一項,當然包括二級和多級數組:
function flatten(arr) { while (arr.some(item => Array.isArray(item))) { // 只要arr中某一項還是數組,則一直執行下去,直到全轉成基本類型數據 arr = [].concat.apply([], arr) // 這里第二個新[]繼承了concat方法,所以能對arr中的元素逐一concat到第二個新[]中。 } return arr }
console.log(arr, flatten(arr)) // [1, 2, 3, 4, Array(3), true] [1, 2, 3, 4, 5, 6, 7, 8, true]
// 第一遍執行返回: [1,2,3,4,[5,6,[7,8]],true] => [1,2,3,4,5,6,[7,8],true],我們看到只處理了第二層數組[5,6,[7,8]],
// 把這個數組當成一項直接concat到新數組,第三層[7,8]沒有處理,但第三層已經變成了第二層,再處理一次即可
// 第二遍執行返回: [1,2,3,4,5,6,[7,8],true] => [1,2,3,4,5,6,7,8,true] 得到我們先要的結果
// 如果還有第四層或更多,while循環會一直執行下去,直到變成一維數組。
4、使用ES6中展開運算符...和while循環,方法3你能理解的話,這個就很好理解了,我不管了,上代碼,自己分析:
function flatten(arr){ while (arr.some(item => Array.isArray(item))){ arr = [].concat(...arr); // 如果你明白展開運算符的作用,是不是很簡單? } return arr; }
5、困難重重的數組扁平化的方法你掌握的差不多了,到了放大招的時候了,ES6總是能讓人出其不意攻其不備,來看看殺手鐧-flat(
depth)
方法會按照一個可指定的深度(depth可以為任意正整數,和Infinity - 任意深度,
默認為1)遞歸遍歷數組,並將所有元素與遍歷到的子數組中的元素合並為一個新數組返回。
var arr= [1,2,3,4,[5,6,[7,8]],true] arr.flat() // [1, 2, 3, 4, 5, 6, Array(2), true]
var arr= [1,2,3,4,[5,6,[7,8]],true] arr.flat(Infinity) // [1, 2, 3, 4, 5, 6, 7, 8, true]
好了,今天主要分析了二維和多維數組降到一維的幾種方法,當然還有其他方法,如果數組中全是數字的話,也可以使用toString()或者join()結合split(),先轉成字符串,再轉成數組的方法:
var arr = [1,2,3,4,[5,6,[7,8]]] function flatten(arr) { return arr.toString().split(',').map(item => { return item - 0 // 字符轉數字: item - 0 , + item , item * 1 , item / 1都能實現 }) } console.log(flatten(arr)) // [1,2,3,4,5,6,7,8]
以上是我對數組扁平化處理方法的理解while遍歷有兩種,分別是apply和ES6展開運算符操作,for循環結合遞歸一種,reduce()遍歷一種,殺手鐧flat()一種。說來說去還是離不開遍歷,現在清楚多了,如果你有好的想法,歡迎分享出來。