# 4. 迴圈

## I. 迴圈的用途

* 重複地做一樣的事情
* 用某個條件判斷決定是否結束不斷重複的輪迴

> 想想看，日常生活中有那些不斷重複做的事情呢?&#x20;

![](https://i.imgur.com/19fgraj.png)

在Python程式語言當中，迴圈有兩種表示方法：`while` 和 `for`

## II. `while`迴圈

### A. `while`迴圈的基本架構

```python
count = 0   # step1. while迴圈前需要一個計圈變數用於計算迴圈執行了幾圈

while count < 10:  # step2. while後方須接上判斷條件，判斷正確即可進入迴圈

    print(count)   # step3. 須要重複做的事

    count += 1   # step4. 迴圈將結束前，將計圈變數做點變化(否則會成為無窮迴圈)
```

> &#x20;執行步驟：step1 → step2 → step3 → step4 → (step2 → step3 → step4)×n次

**注意!** **縮排**也別忘了唷!

**注意!** step1 (計圈變數) 通常有各式型態，接下來我們就會陸續見到

`while`迴圈撰寫時可能會遇到的錯誤情況

```python
# 沒有於迴圈前有個計圈變數的情況
while count < 10: # NameError: name 'i' is not defined
    print(count)
    count += 1
```

```python
# 計圈變數放置於迴圈內的情況
while count < 10: # NameError: name 'i' is not defined
    count = 0
    print(count)
    count += 1
```

```python
# 沒有在迴圈將結束前，將計圈變數做變化
count = 0
while count < 10: # 永遠滿足判斷條件(無法跳出迴圈)
    print(count)
```

```python
# 判斷條件永遠錯誤，無法進入迴圈
count = 11
while count < 10: # 永遠無法滿足判斷條件(無法進入迴圈)
    print(count)
    count += 1
```

【下方為正確撰寫方式】

```python
# 嘗試執行下方的程式碼並觀察結果
count = 0
while 0:
    print(count)
    count += 1
```

```python
# 嘗試執行下方的程式碼並觀察結果
count = 0
while 2 and count < 15 or False:
    print(count)
    count += 1
```

```python
# 嘗試執行下方的程式碼並觀察結果
count = 8
while count < 16:
    print(count)
    count += 2
```

【例題1】

> &#x20;小蚯很喜歡`~`符號\
> &#x20;請寫一個程式能夠讀入一個整數\
> &#x20;再印出該整數個`~`符號

```python
count = int(input("請輸入次數：")) # 先利用一個變數儲存所輸入的整數

i = 0  # 計圈用變數
while i < count:  # 圈數還沒達到目標時
    print('~', end='') 
    i += 1  # 改變計圈用變數的值
```

【例題2】

> &#x20;家裡最近領養了一頭神牛超會算數學，只要給他一個數字，他就能加總出從1到該數字的總和\
> &#x20;**輸入說明**\
> &#x20;讓使用者能夠輸入一個正整數\
> &#x20;**輸出說明**\
> &#x20;若輸入值為10，則輸出55

```python
n = int(input("請輸入次數："))

i = 1 # 計圈用變數
sum = 0 # 創造一個變數用來儲存每一輪迴圈計算出的值

while i <= n:  # 圈數還沒達到n時繼續
    sum += i  # 將每輪計算出的結果儲存在sum變數中
    i += 1  # 改變計圈用變數的值

print(sum)
```

### B. 多變的迴圈

有時候，我們不必使用計圈變數來控制迴圈次數，而是直接改變`while`的判斷條件來讓迴圈停止

&#x20;通常這種寫法用於不確定迴圈需要進行幾圈的情況下

【例題1】

> 小奇有一個很特殊的個性，就是非常討厭偶數，只要看到偶數，就會反覆把它除以二，直到這個數字變成奇數為止。若現在給一個正整數，請問這個數字經過小奇的處理之後，會變成多少呢？

```python
i = int(input('請輸入一個正整數：'))

while i % 2 == 0: # 如果 i 為偶數，就進入迴圈
    i /= 2 # 每一輪將i值除以2

print(i) # 印出最終已成為奇數的 i 值
```

【例題2】

> &#x20;嘗試輸入各種血型來觀看今年的運勢(輸入`00`可結束此程式)

```python
i = '' # 先將i初始為一個非00的值(為了能進入迴圈)

while i != '00': # 當輸入值為00時結束迴圈
    i = input('請輸入一個血型：')
    if i == 'A' or i == 'a':
        print('今年桃花運很旺')
    elif i == 'B' or i == 'b':
        print('今年金錢運很旺')
    elif i == 'AB' or i == 'ab':
        print('今年工作運很旺')
    elif i == 'O' or i == 'o':
        print('今年驚喜運很旺')

print('程式已結束') # 印出 程式已結束 字樣
```

偶爾，我們會期待迴圈能永遠執行下去，永不停止

【例題3】

> 請撰寫一個能讓使用者輸入成績進而判斷：及格、可補考、死當

```python
# 結合了迴圈，就能夠實現重複不斷輸入的效果
while 1:
    num = int(input("請輸入一個分數:"))
    if num >= 60:
        print("及格")
    elif 40 <= num <60:
        print("可補考")
    else:
        print("死當")
```

【例題4】

> 請撰寫一個能夠不斷印出小印地安人的程式

```python
# 結合了迴圈，就能夠實現重複不斷輸入的效果
i = 1  # 計圈變數一開始設為1
while True:
    print(i, 'little Indian')
    i += 1  # 每輪結束前將計圈變數做變化
```

### C. 讓迴圈中途停止或跳過迴圈中的某圈

#### `break`

從上方【例題2】中我們可以發現，需要讓迴圈在`i`值為 `'00'` 時結束，須於 `while` 外頭先宣告 `i` 變數，讓程式碼看起來似乎有那麼一點不完美，這時，若我們能使用`break`即能夠避免這樣的情形

> `break`：當電腦執行到`break`時會**立即**終止**該層**迴圈

【例題】

上方【例題2】的改寫

```python
# 嘗試執行下方的程式碼並觀察結果
while True: 
    i = input('請輸入一個血型：')
    if i == '00':
        break   # 當輸入值為00時結束迴圈
    elif i == 'A' or i == 'a':
        print('今年桃花運很旺')
    elif i == 'B' or i == 'b':
        print('今年金錢運很旺')
    elif i == 'AB' or i == 'ab':
        print('今年工作運很旺')
    elif i == 'O' or i == 'o':
        print('今年驚喜運很旺')

print('程式已結束') # 印出 程式已結束 字樣
```

#### `continue`

偶爾，我們會希望當某個條件成立時，不做某件事而直接進行下一輪迴圈，這時，我們就可以使用`continue`

> `continue`：當電腦執行到`continue`時會**立即**跳過該輪迴圈，直接進行下一輪

【例題】

請製作一個倒數器，讓使用者輸入一個正整數後，即從該正整數開始不斷 -1 直至數到 1 為止，但中間過程若數到 5 的倍數，請跳過

```python
i = int(input('請輸入一個正整數：'))

while i: 
    if i % 5 == 0:
        i -= 1 # 這裡也必須要 -1 否則會形成無窮迴圈(為什麼？)
        continue # 立刻進行下一輪迴圈
    else:
        print(i, end=' ')
        i -= 1
```

想想看，上方的 `i -= 1` 與 `continue` 可以互換位置嗎?

由於`continue`的特性，我們其實能省略`else`，因此可將上方程式碼改寫如下：

```python
i = int(input('請輸入一個正整數：'))

while i: 
    if i % 5 == 0:
        i -= 1
        continue
    print(i, end=' ')
    i -= 1
```

## III. `for`迴圈

`for`迴圈跟`while`迴圈用法相似，最主要區別是在`while`迴圈通常會用於不知道要執行多少圈的情況下，而`for`迴圈通常用在已經知道要執行多少次的情況\
&#x20;例如：\\

> &#x20;1\. 印出100個`Hello`\
> &#x20;2\. 算出某個數字的某次方\
> &#x20;3\. 算出某個數字的階乘

**注意!** 若不希望計圈變數在每一圈的變化值都相同，使用`while`會優於用`for`

### A. `for`迴圈的基本架構

`for`迴圈中也必須有一個計圈變數用來計算目前執行了幾圈，只是計圈變數放在`for`迴圈結構中。 【每輪迴圈完畢後，計算圈數的變數會產生變動】

以下三種為`for`迴圈常見的架構

```python
# range內只放一個數的情況
for i in range(6): # i會從0-5(不包含6)，每輪i都會+1
    print(i)
```

```python
# range內放兩個數的情況
for c in range(2, 6): # c會從2-5(不包含6)，每輪c都會+1
    print(c)

for c in range(-6, 2):  # c會從-6~1(不包含2)，每輪c都會+1
    print(c)
```

```python
# range內放三個數的情況
for x in range(21, 6, -3): # x會從21-6(不包含6)，每輪x都會-3
    print(x)
```

### B. `for` 與 `while` 間的轉換

兩者功能相同，也都需要一個計圈變數來記錄總共跑了幾圈。(唯`while`較簡便使用於無窮迴圈的情況下)

【例題】

```python
for i in range(6):
    print(i)

# 可改寫為：

i = 0
while i < 6:
    print(i)
    i += 1
```

```python
for c in range(2, 6):
    print(c)

# 可改寫為：

c = 2
while c < 6:
    print(c)
    c += 1
```

```python
for x in range(21, 6, -3):
    print(x)

# 可改寫為：

x = 21
while x > 6:
    print(x)
    x -= 3
```

### C. `for` 迴圈的計圈變數

`for` 迴圈中的計圈變數`i`沒辦法於`range`範圍中做更動，舉個範例如下

```python
for i in range(2,5):
    i=1 # 將計圈變數改為1
    print(i, end=' ') # 印出計圈變數
# 執行結果為：1 1 1 
```

即使想將過程中的`i`改為1，但在`range`中實際上它仍是2 3 4 ，因為在執行`range`時，它就已經將`i`值存在一個陣列中，無法更動

### 補充：迴圈搭配 `else`

`python`的迴圈有個很特殊的用法，即是能夠搭配`else`使用，若迴圈沒有在中途結束執行，就會執行`else`，舉個範例如下

```python
for i in range(3):
    print(3, end='')
else:
    print("前面迴圈沒有中斷")

# 執行結果為：&&&前面迴圈沒有中斷
```

```python
for i in range(3):
    print(3, end='')
    if i==2:
        break
else:
    print("前面迴圈沒有中斷")

# 執行結果為：&&&
```

## IV. 巢狀迴圈

### A. 巢狀迴圈的意義

巢狀迴圈顧名思義就是迴圈中還有迴圈的概念囉\~\~

> 相信大家對積木程式都已經不陌生了，先回想看看這題應該如何解? ![](https://i.imgur.com/v9qk0Zp.png)

先利用迴圈走完一個小三角形 ![](https://i.imgur.com/cUnh6EU.png)

再利用一個迴圈走完12個相同的小三角形 ![](https://i.imgur.com/ytncKoy.png)\
&#x20;

### B. 巢狀迴圈的範例

【例題1】

> &#x20;據說變態的人都喜歡打`A`\
> &#x20;設計一個能讓使用者輸入**列**和**行**的程式\
> &#x20;例如：列為3，行為5時，輸出：\
> &#x20;AAAAA\
> &#x20;AAAAA\
> &#x20;AAAAA

{% hint style="info" %}
思路：

1\. 印出A

2\. 重複?次

3\. 換一行

4\. 1\~3重複?次
{% endhint %}

```python
row, col = map(int, input("請輸入列與行：").split())

# 跑row圈(印出row個橫列)
for i in range(0, row): 

    # 跑col圈(在第i圈印出col個A)
    for j in range(0, col): 
        print("A", end="")

    print()
```

#### 用`while`改寫

```python
row, col = map(int, input("請輸入列與行：").split())

# 跑row圈(印出row個橫列)
i = 0
while i < row: 

    # 跑col圈(在第i圈印出col個A)
    j = 0 # 思考看看，如果此行與上一行程式碼位置互換結果會如何?
    while j < col: 
        print('A', end='')
        j += 1 
    print()
    i += 1 # 想想看，這行程式碼位什麼要往前移動
```

【例題2】

> &#x20;輸入n，輸出n行星號，第一行有一個\
> &#x20;每往下一行，就多一個星號\
> &#x20;例如：n為4時，輸出如下\
> &#x20;\*\
> &#x20;\*\*\
> &#x20;\*\*\*\
> &#x20;\*\*\*\*

{% hint style="info" %}
思路：

1\. 印出" "

2\. 重複?次

3\. 印出"\*"

4\. 重複?次

5\. 換一行

6\. 1\~5重複?次
{% endhint %}

```python
n = int(input("請輸入一個正整數："))

# 跑n圈(印出n個橫列)
for i in range(0, n): 

    # 每一輪j值的上限隨i變化而變化(即：在第i圈印出ｉ個＊)
    for j in range(0, i+1): 
        print("*", end="")

    print()
```

思考看看，第二個`for`迴圈為何上限寫`i+1`而非`i`

你也可以這樣改寫

```python
n = int(input("請輸入一個正整數："))

# 跑n圈(印出n個橫列)
for i in range(1, n+1):

    # 每一輪j值的上限隨i變化而變化(即：在第i圈印出ｉ個＊)
    for j in range(0, i):
        print("*", end="")

    print()
```

用`while`改寫

```python
n = int(input("請輸入一個正整數："))

# 跑n圈(印出n個橫列)
i = 1
while i < n+1: 

    # 每一輪j值的上限隨i變化而變化(即：在第i圈印出ｉ個＊)
    j = 0
    while j < i: 
        print('*', end='')
        j += 1

    print() 
    i += 1
```

### C. 巢狀迴圈中的 `continue` 與 `break`

**`break`**&#x8207;**`continue`**&#x90FD;僅作用於本身所存在的該層迴圈而已

```python
for i in range(5):
    for j in range(5):
        if j == 3:
            continue
        elif j == 4:
            break
        print(j, end=' ')
    print()
```

上方程式碼執行後的結果如下：

```python
0 1 2 
0 1 2 
0 1 2 
0 1 2 
0 1 2
```

## III. 學習單

{% embed url="<https://docs.google.com/presentation/d/e/2PACX-1vStIb8amiWJSmiy2NIncHlyRTyU9GlQ23g7Q3ot1dT8FBLoXk9P37ufONLXgzA30EwFr7hx25hbwd6Y/embed?start=false&loop=false&delayms=3000>" %}
