陣列concat_精學手撕系列——陣列扁平化
技術標籤:陣列concat
參考文章:面試官連環追問:陣列拍平(扁平化) flat 方法實現
編者薦語:
在前端面試中,手寫flat
是非常基礎的面試題,通常出現在筆試或者第一輪面試中,主要考察面試者基本的手寫程式碼能力和JavaScript
的基本功。
今天就帶大家從0瞭解flat
特性到手寫實現flat
,再到接住面試官的連環追問中重新學習一遍陣列扁平化flat
方法
Array.prototype.flat()
一段程式碼總結Array.prototype.flat()
特性
注:陣列拍平方法
Array.prototype.flat()
也叫陣列扁平化、陣列拉平、陣列降維。
letarr=[12,23,[34,56,[78,90,100,[110,120,130]]]];
console.log(arr.flat());
//[12,23,34,56,[78,90,100,[110,120,130]]]
console.log(arr.flat(2));
//[12,23,34,56,78,90,100,[110,120,130]]
console.log(arr.flat(Infinity));
//[12,23,34,56,78,90,100,110,120,130]
console.log(arr.flat(0));
//[12,23,[34,56,[78,90,100,[110,120,130]]]];
console.log(arr.flat(-10));
//[12,23,[34,56,[78,90,100,[110,120,130]]]];
letarr2=[12,23,[34,56,,]]
console.log(arr.flat());
//[12,23,34,56]
Array.prototype.flat()
特性總結
Array.prototype.flat()
用於將巢狀的陣列“拉平”,變成一維的陣列。該方法返回一個新陣列,對原資料沒有影響。不傳引數時,預設“拉平”一層,可以傳入一個整數,表示想要“拉平”的層數。
傳入
<=0
的整數將返回原陣列,不“拉平”Infinity
關鍵字作為引數時,無論多少層巢狀,都會轉為一維陣列如果原陣列有空位,
Array.prototype.flat()
會跳過空位。
面試官 N 連問:
第一問:下面陣列如何實現扁平化?
letarr=[
[1,2,2],
[3,4,5,5],
[6,7,8,9,[11,12,[12,13,[14]]]],10
];
小夥伴首先想到的肯定是用 ES6 的Array.prototype.flat
方法呀
方法一:flat
arr=arr.flat(2);
//[1,2,2,3,4,5,5,6,7,8,9,11,12,[12,13,[14]],10]
當flat
中傳入數字時,是扁平對應的層數,顯然這不是我們想要的,因為它還沒有完全展開。
這是,flat
函式中就為我們提供了一個引數Infinity
,譯為無窮
的意思。
arr=arr.flat(Infinity);
/*[
1,2,2,3,4,5,5,
6,7,8,9,11,12,12,
13,14,10
]*/
當我們不知道陣列中嵌套了幾維陣列時,我們可以用Infinity
這個引數,幫我們全部展開。
第二問:還有其它的辦法嗎?因為它們在高版本瀏覽器並不相容
方法二:轉換為字串,再把字串物件用,轉換成陣列
可以先把多維陣列
先轉換為字串
,再基於,
分隔符將字串物件
分割成字串陣列
toString()
扁平化陣列
arr=arr.toString();
//"1,2,2,3,4,5,5,6,7,8,9,11,12,12,13,14,10"
arr=arr.toString().split(',');
//["1","2","2","3","4","5","5","6","7","8","9","11","12","12","13","14","10"]
arr=arr.toString().split(',').map(item=>parseFloat(item));
//[1,2,2,3,4,5,5,6,7,8,9,11,12,12,13,14,10]
除了上面的方法還有什麼方法轉換為字串呢?
JSON.stringify()
扁平化陣列
arr=JSON.stringify(arr);
//"[[1,2,2],[3,4,5,5],[6,7,8,9,[11,12,[12,13,[14]]]],10]"
arr=JSON.stringify(arr).replace(/(\[|\])/g,'');
//"1,2,2,3,4,5,5,6,7,8,9,11,12,12,13,14,10"
arr=JSON.stringify(arr).replace(/(\[|\])/g,'').split(',').map(item=>parseFloat(item));
//[1,2,2,3,4,5,5,6,7,8,9,11,12,12,13,14,10]
方法三:迴圈驗證是否為陣列
基於陣列的some
方法,只要數組裡面有一項元素是陣列就繼續迴圈,扁平陣列
核心:[].concat(...arr)
whilte(arr.some(item=>Array.isArray(item))){
arr=[].concat(...arr);
}
console.log(arr);//[1,2,2,3,4,5,5,6,7,8,9,11,12,12,13,14,10]
第三問:能自己實現一個 flat 扁平化嗎?
先回答:能!!再跟著我分析思路:
如何實現呢,其實思路非常簡單:在陣列中找到是陣列型別的元素,然後將他們展開
,這就是flat
方法的關鍵思路
實現思路:
- 迴圈數組裡的每一個元素
- 判斷該元素是否為陣列
- 是陣列的話,繼續迴圈遍歷這個元素——陣列
- 不是陣列的話,把元素新增到新的陣列中
實現流程:
- 建立一個空陣列,用來儲存遍歷到的非陣列元素
- 建立一個迴圈遍歷陣列的函式,cycleArray
- 取得陣列中的每一項,驗證
Array.isArray()
- 陣列的話,繼續迴圈
- 非陣列的話,新增到新陣列中
- 返回新陣列物件
ES5 實現 flat 扁平化方法
letarr=[
[1,2,2],
[3,4,5,5],
[6,7,8,9,[11,12,[12,13,[14]]]],10
];
functionmyFlat(){
_this=this;//儲存 this:arr
letnewArr=[];
//迴圈arr中的每一項,把不是陣列的元素儲存到newArr中
letcycleArray=(arr)=>{
for(leti=0;iletitem=arr[i];
if(Array.isArray(item)){//元素是陣列的話,繼續迴圈遍歷該陣列
cycleArray(item);
continue;
}else{
newArr.push(item);//不是陣列的話,直接新增到新陣列中
}
}
}
cycleArray(_this);//迴圈數組裡的每個元素
returnnewArr;//返回新的陣列物件
}
Array.prototype.myFlat=myFlat;
arr=arr.myFlat();//[1,2,2,3,4,5,5,6,7,8,9,11,12,12,13,14,10]
ES6 實現 flat 扁平化方法
constmyFlat=(arr)=>{
letnewArr=[];
letcycleArray=(arr)=>{
for(leti=0;iletitem=arr[i];
if(Array.isArray(item)){
cycleArray(item);
continue;
}else{
newArr.push(item);
}
}
}
cycleArray(arr);
returnnewArr;
}
myFlat(arr);//[1,2,2,3,4,5,5,6,7,8,9,11,12,12,13,14,10]
第四問:請使用reduce
實現flat
函式
相信很多面試官都會指定讓面試者用reduce
方法實現flat
函式
其實思路也是一樣的,在實現之前,先來看一下
它的核心:
[].concat(...arr)
但是它只能將陣列元素展開一層,來看下面例子:
letarr2=[12,23,[34,56,[78,90,100]]];
[].concat(...arr2);
//[12,23,34,56,[78,90,100]]
細心的同學可以發現[].concat(...arr)
只能展開一層陣列元素,當有更深層次的,是無法展開的
接下來,我們來看看用reduce
怎麼實現?
letarr=[12,23,[34,56,[78,90,100,[110,120,130,140]]]];
constmyFlat=arr=>{
returnarr.reduce((pre,cur)=>{
returnpre.concat(cur);
},[]);
};
console.log(myFlat(arr));
//[12,23,34,56,[78,90,100,[110,120,130,140]]]
constmyFlat=arr=>{
returnarr.reduce((pre,cur)=>{
returnpre.concat(Array.isArray(cur)?myFlat(cur):cur);
},[]);
};
console.log(myFlat(arr));
//[12,23,34,56,78,90,100,110,120,130,140]
上面程式碼中的Array.isArray(cur)
和myFlat(cur)
實際就好比與遍歷陣列每一項,看它是不是陣列元素,
如果是的話,則繼續遞迴遍歷,不是的話直接數組合並非陣列元素
。
第五問:使用棧的思想實現flat
函式
棧思想: 後進先出的資料結構
實現思路:
不斷獲取並刪除棧中最後一個元素
A
,判斷A
是否為陣列元素,直到棧內元素為空,全部新增到newArr
- 是陣列,則
push
到棧中,繼續迴圈棧內元素
,直到棧為空- 不是陣列,則
unshift
新增到newArr
中
//棧思想
functionflat(arr){
constnewArr=[];
conststack=[].concat(arr);//將陣列元素拷貝至棧,直接賦值會改變原陣列
//如果棧不為空,則迴圈遍歷
while(stack.length!==0){
constval=stack.pop();//刪除陣列最後一個元素,並獲取它
if(Array.isArray(val)){
stack.push(...val);//如果是陣列再次入棧,並且展開了一層
}else{
newArr.unshift(val);//如果不是陣列就將其取出來放入結果陣列中
}
}
returnnewArr;
}
letarr=[12,23,[34,56,[78,90,100,[110,120,130,140]]]];
console.log(flat(arr));
//[12,23,34,56,78,90,100,110,120,130,140]
本文總結
看完這篇文章的同學,可以在面試的時候分類,分思想給面試官描述,可以先說我用哪幾種思想實現過,它們的寫法又分別有什麼不同。
最後希望這篇文章可以幫助到大家,感謝閱讀。
看完三件事❤
如果你覺得這篇內容對你還蠻有幫助,我想邀請你幫我三個小忙:
- 點贊,轉發,有你們的
在看
,才是我創造的動力。 - 關注公眾號 胡哥有話說,不定期分享原創知識。
- 同時可以期待後續文章ing?
胡哥有話說,專注於大前端技術領域,分享前端系統架構,框架實現原理,最新最高效的技術實踐!