# [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;
}
```
:::