1. 程式人生 > 其它 >陣列concat_精學手撕系列——陣列扁平化

陣列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方法的關鍵思路

實現思路:

  • 迴圈數組裡的每一個元素
  • 判斷該元素是否為陣列
    • 是陣列的話,繼續迴圈遍歷這個元素——陣列
    • 不是陣列的話,把元素新增到新的陣列中

實現流程:

  1. 建立一個空陣列,用來儲存遍歷到的非陣列元素
  2. 建立一個迴圈遍歷陣列的函式,cycleArray
  3. 取得陣列中的每一項,驗證Array.isArray()
  • 陣列的話,繼續迴圈
  • 非陣列的話,新增到新陣列中
  1. 返回新陣列物件

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]

本文總結

看完這篇文章的同學,可以在面試的時候分類,分思想給面試官描述,可以先說我用哪幾種思想實現過,它們的寫法又分別有什麼不同。

最後希望這篇文章可以幫助到大家,感謝閱讀。

看完三件事❤

如果你覺得這篇內容對你還蠻有幫助,我想邀請你幫我三個小忙:

  1. 點贊,轉發,有你們的 在看,才是我創造的動力。
  2. 關注公眾號 胡哥有話說,不定期分享原創知識。
  3. 同時可以期待後續文章ing?

胡哥有話說,專注於大前端技術領域,分享前端系統架構,框架實現原理,最新最高效的技術實踐!

c88e5a2b5b741245cd0b1a98e2b2617d.png