讓我豆頁痛的遞迴。
常犯的錯誤
使用 join() 與 split()。
我一開始想到的也是這種作法,但後來才知道這種做法會有問題:
1 2 3 4 5 6
| function flatten(arr) { return arr.join(',').split(',') } console.log(flatten([1, 2, 3])) console.log(flatten([1, 2, 3, [1, 2], [3, 4], 5])) console.log(flatten([1, 2, 3, [1, [2]], [3, 4, [5]], 6]))
|
(最後會變成字串是因為 join 會強制把元素轉成字串)
其實這個做法在大部分的情況下都沒有問題,唯獨在元素剛好是 「,」 的時候會出問題。
1 2 3 4
| function flatten(arr) { return arr.join(',').split(',') } console.log(flatten(['1,', 2, 3]))
|
原因是因為:
join 後會變成 => '1,,2,3'
split 後會變成 => ['1', '', '2', '3']
忘記這兩個的作用可以參考 陣列的內建函式 跟 跟字串有關的內建函式
所以這個方法對會出現逗號的 case 都無法使用。
正確的作法
利用遞迴的概念來實作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| function flatten(arr) { const result = [] arr.forEach(item => { if(Array.isArray(item)) { const flattenArray = flatten(item) flattenArray.forEach(item => result.push(item)) } else { result.push(item) } }) return result }
console.log(flatten([1, 2, 3])) console.log(flatten([1, 2, 3, [1, 2], [3, 4], 5])) console.log(flatten([1, 2, 3, [1, [2]], [3, 4, [5]], 6])) console.log(flatten(['1,', 2, 3]))
|
這題的思路是這樣子:
- 建立一個
result,用來儲存壓平後的陣列
- 遍歷傳入的
arr,如果元素不是陣列,直接推入 result
- 如果是陣列,再把它壓平
重點在於第三步的時候,你會想說「這不就是我正要做的事情嗎?」,所以會感到很疑惑。
但其實不用想的太複雜,你只要知道 flatten 這個 function 最後就是會回傳一個「壓平後的陣列」,所以直接給它呼叫下去就對了。不管這個過程會重複呼叫幾次 flatten,最後都一定會有盡頭(當元素不再是陣列的時候,就會被推到 result)。