# [Codewars] Snail ###### tags: `解題筆記` ## 練習資訊 等級:4 kyu 題目:[Snail](https://www.codewars.com/kata/521c2db8ddc89b9b7a0000c1/javascript) 練習時間: - 2023/06/18(想了一陣子想不到,所以有速瞄別人解題的答案) ## 題目說明 ### 中文 給一組二維陣列,最後必須按照蝸牛殼紋路產出一維陣列。 ### 英文 Snail Sort Given an n x n array, return the array elements arranged from outermost elements to the middle element, traveling clockwise. ```javascript! array = [[1,2,3], [4,5,6], [7,8,9]] snail(array) #=> [1,2,3,6,9,8,7,4,5] ``` For better understanding, please follow the numbers of the next array consecutively: ```javascript! array = [[1,2,3], [8,9,4], [7,6,5]] snail(array) #=> [1,2,3,4,5,6,7,8,9] ``` NOTE: The idea is not sort the elements from the lowest value to the highest; the idea is to traverse the 2-d array in a clockwise snailshell pattern. NOTE 2: The 0x0 (empty matrix) is represented as en empty array inside an array [[]]. ## 我的方法 ### 思路 - 需要重複到條件結束為止,所以主要的遍歷用 `while` 而不是依靠 elements 決定遍歷的次數的 `for...` 迴圈家族 - 要模擬蝸牛殼的紋路,找出紋路的規律 - 第一排 - 最右邊 - 最下面 - 最左邊 - 透過 mutable 的更改方式(`Array.pop()`, `Array.shift()`)修改 + 取得指定 element,並且將原陣列當作 `while` 的 flag ### 程式碼 ```javascript= snail = function (array) { const result = []; // 使用 mutable 的方式修改,並且把原陣列當作是否執行 while 的 flag while (array.length > 0) { // 第一排移動 result.push(...array.shift()); // 最右邊移動 for (let i = 0; i < array.length; i++) { result.push(array[i].pop()); } // 最下面移動 const bottomElements = array.pop(); if (Array.isArray(bottomElements)) { result.push(...bottomElements.reverse()); } // 最左邊移動 const leftMovements = []; for (let i = 0; i < array.length; i++) { leftMovements.push(array[i].shift()); } result.push(...leftMovements.reverse()); } return result }; ``` ## 厲害的解答 ### 思路 - 使用 `while` + mutable 更新原來陣列當作 flag - 也是按照蝸牛殼的紋路判斷方向執行(但是透過 `Array.concat()` + 三元的判斷更簡潔結果的組成 - 第一排 - 最右邊 - 最下面 - 最左邊 - 最左邊的紋路透過 `for` 遍歷,直接從最後慢慢往前取,就不用想我一樣正序取完再透過 `Array.reverse()` 多一次迴圈反轉 :::spoiler ```javascript= snail = function(array) { var result; while (array.length) { // Steal the first row. result = (result ? result.concat(array.shift()) : array.shift()); // Steal the right items. for (var i = 0; i < array.length; i++) result.push(array[i].pop()); // Steal the bottom row. result = result.concat((array.pop() || []).reverse()); // Steal the left items. for (var i = array.length - 1; i >= 0; i--) result.push(array[i].shift()); } return result; } ``` :::