---
# System prepended metadata

title: '[Codewars] Snail'
tags: [解題筆記]

---

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




