數組的元素可能是數組,這樣一層層嵌套,可能得到一個嵌套很深的數組,數組降維要做的事就是把嵌套很深的數組展開,一般最后得到一個一維數組,其中的元素都是非數組元素,比如數組[1, [2, 3, [4, 5], 6], 7, 8]降維展開后是[1, 2, 3, 4, 5, 6, 7, 8].
1.普通方法
function flattenMd(arr){
var result=[]
function flatten(arr){
for (var i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
flatten(arr[i]);
}else{
result.push(arr[i]);
}
}
}
flatten(arr);
return result;
}
var arr=[1, [2, 3, [4, 5], 6], 7, 8]
console.log(flattenMd(arr));[ 1, 2, 3, 4, 5, 6, 7, 8 ]
備注:這里我使用了Array.isArray()方法來檢測對象時候是數組,沒有考慮ES5以下的兼容性,關於js對象類型的檢測可以參考我的另一篇博文Javascript數據類型檢測,當然了如果支持ES5的話,還可以直接使用數組的迭代方法forEach(或map、reduce等),Es6中還有for···in可以使用,這里就不贅述了。
這個方法需要定義兩個函數,其中flatten方法位於內部。還可以改造成閉包的形式
function flattenMd(ret) {
function flatten(arr) {
arr.forEach(function(item) {
(Array.isArray(item)) ? flatten(item) : ret.push(item);
});
}
return function(arr) {
flatten(arr);
return ret;
}
}([]);
var arr=[1, [2, 3, [4, 5], 6], 7, 8]
console.log(flattenMd(arr));[ 1, 2, 3, 4, 5, 6, 7, 8 ]
2.數組concat方法
熟悉數組操作方法的開發人員應該知道數組concat方法的特性:傳遞給concat方法的參數序列中如果包含數組,則會將這個數組的每一項添加到結果數組中,這就使數組的這個方法具有了天然的展開二維數組的能力,比如:
var colors=['red','green','blue'];
var colors2=colors.concat('yellow',['black','brown']);
console.log(colors2)//[ 'red', 'green', 'blue', 'yellow', 'black', 'brown' ]
需要注意的是如果數組的元素還是數組則不會再展開了,也就是concat方法只能降低一維。借助concat方法,可以得到另一種二維數組降維方法。
function flatten2d(arr) {
var result = [];
for(var i = 0; i < arr.length; i++) {
result = result.concat(arr[i]);
}
return result;
}
上面的方法還可以進一步簡化。我們知道apply方法是可以直接接受數組參數,這樣我們連循環迭代都省了。
function flatten2d(arr) {
return Array.prototype.concat.apply([], arr);
}
網上很多博客說使用遞歸很容易將二維的降維改造成多維的降維,實際上操作起來是比較復雜的,因為沒有現成的方法能夠判斷某個數組是不是二維數組,也就不能判斷遞歸的結束條件了。所以對於多維數組的降維需要重新規划使用concat方法可以避免方法一中多出的內部函數
對於多維數組
function flattenMd(arr) {
var result = [];
for(var i = 0; i < arr.length; i++){
if(arr[i] instanceof Array) {
result = result.concat(flattenMd(arr[i]));
}
else {
result.push(arr[i]);
}
}
return result;
}
var arr=[1, [2, 3, [4, 5], 6], 7, 8]
console.log(flattenMd(arr));[ 1, 2, 3, 4, 5, 6, 7, 8 ]
3.數組join和split方法的結合(有缺陷)
很多開發人員都知道數組的join方法可以將數組展開成字符串,但是不確定的是join方法能夠展平數組,即使是多維數組,我們再使用split方法重新組合數組就行了。但是這個方法有天然缺陷,下面的例子中會看到
function flattenMd(arr) {
return arr.join().split(',');
}
var arr=['1', [null, 3, [4, 5], {K:1}], undefined, 8]
console.log(flattenMd(arr));//[ '1', '', '3', '4', '5', '[object Object]', '', '8' ]
從結果可以看出,這樣處理過后有幾個缺點:一是所有類型的元素都會變成字符串;二是null、undefined會變成空字符串、對象會變成'[object Object]'。相當於調用了toString方法,當也不是說這個方法一無是處。對於同一種類型的元素,還是很有用處的,比如要求多維數組的最大值。
function flattenMd(arr) {
return arr.join().split(',');
}
var arr=[1, [5, 3, [8, 5], 5,[15]], 9, 13]
console.log(Math.max.apply(null,flattenMd(arr)));//15
4.最佳實踐方法
function flatten(arr) {
return arr.reduce((prev, cur) => {
return plane.concat(Array.isArray(cur) ? flatten(cur) : cur);
}, []);
}
function deepFlatten(arr) {
flatten = arr => [].concat(...arr);
return flatten(arr.map(item => (Array.isArray(item) ? deepFlatten(item) : item)));
}
