# Lesson 2 | 條件判斷與迴圈 ## 第一節:熟悉資料型態(1) 在撰寫條件判斷與迴圈之前,我們先正式介紹一下Python裡面常用的內建型態(Built-in Types)。 * 布林(Boolean): * True, False * 數字類型(Numeric Types): * int, float, complex * 文本序列類型(Text sequence Type): * str * 序列類型(Sequence Types): * list, tuple, range * 集合類型(Set Types): * set * 映射類型(Mapping Types): * dict ## 第一節:熟悉資料型態(2) * 先不要被一大堆定義給嚇到,我們可以將資料型態粗略分為數字跟文字。而以下這些常用的基本函式相當重要: * type() - 用來查詢變數的資料型態。 * XXX() - XXX為資料型態的名稱,用來創建或轉換資料型態。 * 首先來體驗一下"單個"的資料,我們可以使用對應到資料型態的函式來創建變數。 * bool ```python= a = True print('type of a: ', type(a)) b = bool(True) print('type of b: ', type(b)) ``` * int ```python= c = 16 print('type of c: ', type(c)) d = int(16) print('type of d: ', type(d)) ``` * float ```python= e = 5. print('type of e: ', type(e)) f = float(5.3) print('type of f: ', type(f)) ``` * complex ```python= g = 1+5j print('type of g: ', type(g)) h = complex(1, 5) print('type of h: ', type(h)) ``` * str ```python= i = 'ABCD' print('type of i: ', type(i)) j = str('ABCD') print('type of j: ', type(j)) k = str('1234') print('type of k: ', type(k)) ``` * 創建資料型態的函式也可以用來轉換資料型態。 * 舉例來說,文本可以被轉換成數字。 ```python= str_2_int = int('9452') print(str_2_int) print('type of str_2_int: ', type(str_2_int)) str_2_float = float('9452.087') print(str_2_float) print('type of str_2_float: ', type(str_2_float)) ``` * 數字間int與float的轉換。 ```python= float_2_int = int(9452.087) print(float_2_int) print("type of float_2_int: ", type(float_2_int)) ``` ## 第一節:熟悉資料型態(3) * 接下來我們嘗試可以儲存"多個變數"的資料型態。 * list ```python= list_a = [1, 2, 3, 4, "5"] print("type of list_a: ", type(list_a)) ``` * tuple - 可視為不可修改內部元素的list。 ```python= tuple_a = (1, 2, 3, 4, "5") print("type of tuple_a: ", type(tuple_a)) tuple_b = tuple([1, 2, 3, 4, "5"]) print("type of tuple_b: ", type(tuple_b)) tuple_a[0] = 1 ``` * set - 能讓輸入的元素變成"唯一"。 ```python= set_a = {1, 2, 3, 4, 4} print(set_a) print("type of set_a: ", type(set_a)) set_b = set([1, 87, 87, 2, 3]) print(set_b) print("type of set_b: ", type(set_b)) ``` * dict - 可視為能為內部元素命名的list。 ```python= dict_a = {'a': 1, 'b': 2} print("type of dict_a: ", type(dict_a)) dict_b = dict(a = 1, b = 2) print("type of dict_b: ", type(dict_b)) ``` * 而以下這些基本函式常在這個層級上使用: * len() - 用來查詢該變數的長度,變數數目。 ```python= list_a = [1, 2, 3, 4, "5"] len(list_a) ``` * range() - 則是一個比較特別的資料型態,我們常用它來創造數字序列。 ```python= range_10 = range(10) print("type of range_10: ", type(range_10)) print(list(range_10)) ``` ## 練習1:熟悉函數組合 * 請各位幫我查看一下這個變數。 ```python= x = [16, 6, 13, 1, 3, 4, 14, 11, 11, 10, 9, 4, 6, 3, 9, 4, 2, 14, 17, 13, 16, 9, 6, 16, 1, 1, 9, 5, 8, 6, 14, 11, 13, 17, 3, 9, 20, 9, 11, 4, 17, 8, 3, 16, 8, 4, 8, 9, 20, 14, 14, 5, 14, 6, 4, 6, 6, 13, 1, 9, 6, 14, 16, 9, 20, 16, 9, 13, 13, 4, 2, 5, 8, 14, 18, 16, 16, 4, 18, 11, 18, 11, 10, 6, 5, 17, 9, 11, 13, 20, 8, 8, 16, 9, 13, 4, 3, 17, 16, 9, 6, 8, 3, 8, 2, 20, 11, 14, 16, 8, 11, 13, 1, 4, 20, 16, 17, 3, 16, 5, 20, 20, 5, 4, 5, 16, 6, 11, 10, 2, 17, 13, 18, 2, 13, 2, 9, 2, 9, 13, 16, 8, 5, 11, 6, 18, 9, 9, 5, 11, 1, 8, 5, 2, 9, 16, 1, 3, 5, 6, 2, 1, 9, 16, 20, 6, 4, 6, 8, 3, 5, 13, 17, 6, 1, 6, 4, 9, 6, 6, 5, 5, 5, 17, 8, 13] ``` * 問題1:在變數「x」內有共幾「個」數字? <details> <summary>解答</summary> - 答案為186。 ```python= print(len(x)) ``` </details> * 問題2:共有幾「種」數字在變數「x」內? <details> <summary>解答</summary> - 我們可以利用set(),來讓list內的元素變成唯一,答案為16。 ```python= print(len(set(x))) ``` </details> * 問題3:這個數列中缺少了1至20中的哪些數字? <details> <summary>解答</summary> - 這題比較特別,我們可以用肉眼觀察,答案為7、12、15、19。倘若內容物的數字數以百計呢?就需要用到接下來這堂課要介紹的『條件判斷與迴圈』。 ```python= print(set(x)) ``` </details> ## 第二節:條件判斷式(1) * 在Python裡面,要做判斷,常用這幾種「運算」,來回傳布林。 * 布林運算(Boolean Operations):「or」、「and」、「not」、「in」。 ```python= x = True y = False # "or" - 或 print(x or y) # "and" - 且 print(x and y) # "not" - 不是 print(not x) # "in" - 在不在裡面 print(x in [False, False, False, False]) ``` * 比較運算(Comparisons Operations):「<」、「<=」、「>」、「>=」、「==」、 「!=」。 ```python= print(1 < 2) print(2 == 1 + 1) print("Z" > "B") print("同婚" != "性解放") ``` * 我們可以利用這些「運算」的組合,來做更複雜的判斷。 ```python= x = 9 print(x <= 4 and x > 2) print(x > 4 or x <= 2) ``` ## 第二節:條件判斷式(2) * 讓我們來正式介紹條件判斷式,使用在複合語句(Compound Statements)當中的「if」。當「if」後為真時,Python會執行冒號後的程式碼。 * 若A,若A則B。 ```python= if "Z" > "B": x = 2 if "利" > "弊": y = 3 else: y = 4 print(x * y) ``` * 若不是則。 ```python= score = 99 if score >= 90: print('A') elif score >= 75: # else if print('B') elif score >= 60: # else if print('C') else: print('Not pass.') ``` ## 練習2:熟悉條件判斷式 * 我們現在已經可以利用我們所學,建構簡單的應用腳本。請同學們參考[國民健康署網站](https://www.hpa.gov.tw/Pages/Detail.aspx?nodeid=542&pid=705),建立一個BMI指數計算器,以變數儲存身高與體重,讓Python回傳其BMI數值以及體重是否正常,回傳的文字包含"體重過輕"、"健康體重"、"體重過重"或是"肥胖"。 <details> <summary>解答</summary> ```python= height = 163 weight = 60 BMI = (weight / ((height/100)**2)) print("你輸入的BMI為", BMI, " (kg/m^2).") if BMI < 18.5: result = '體重過輕' elif BMI < 24: result = '健康體重' elif BMI < 27: result = '體重過重' else: result = '肥胖' print("體重狀況: ", result) ``` </details> ## 第二節:迴圈(1) * 如果我們要對大量的資料進行重複的計算或判斷呢? * 讓我們觀察「費波納奇數列」:起始數列為1、1,之後每個數為前兩個數之和。 ```python= # 這是一個常用來複製list的方式 x = [0] * 12 # 將前兩個數字皆替換成1。 x[0:2] = 1, 1 x[2] = x[1] + x[0] x[3] = x[2] + x[1] x[4] = x[3] + x[2] x[5] = x[4] + x[3] x[6] = x[5] + x[4] x[7] = x[6] + x[5] x[8] = x[7] + x[6] x[9] = x[8] + x[7] x[10] = x[9] + x[8] x[11] = x[10] + x[9] print(x) ``` * 你是否覺得這樣的運算存在規律?而要怎樣抽解這些規律呢? * 在上述程式碼我們注意到了一件事情,也就是每一行程式碼中索引的位置都會一起增加1。我們現在將使用另一個變數來替換程式碼中共同的部分。 ```python= # 創建一個長度為12,元素皆為0的list。 x = [0] * 12 # 將前兩個數字皆替換成1。 x[0:2] = 1, 1 idx = 2 x[idx] = x[idx - 1] + x[idx - 2] idx = 3 x[idx] = x[idx - 1] + x[idx - 2] idx = 4 x[idx] = x[idx - 1] + x[idx - 2] idx = 5 x[idx] = x[idx - 1] + x[idx - 2] print(x) ``` * 若能定義好變數,讓變數依序改變,我們即可讓程式進行大量運算,這是迴圈的基本邏輯! ## 第二節:迴圈(2) * 讓我們正式介紹第二個常用的複合語句:「for」,「for」會搭配另外一個運算:「in」使用。 * 我們可以把for迴圈翻譯成"讓...在...裡面,使其從頭到尾依序指派..."。 * 這個時候先不要急,我們先藉由這些下列程式碼來理解迴圈。 * 先宣告一個list來存idx,然後我們使用「for」,在for迴圈內會依序指派「in」後面的變數。 ```python= idx_list = list(range(10)) print(idx_list) for idx in idx_list: print(idx) ``` * 我們也可以直接使用range(),range這個資料型態能直接用於迴圈。 ```python= for idx in range(10): print(idx) ``` * 讓我們回到「費波納奇數列」,我們先宣告物件,並使用迴圈進行運算。 ```python= len_of_num = 12 # 創建長度為12,元素皆為0的list。 x = [0] * len_of_num # 將前兩個數字皆替換成1。 x[0:2] = 1, 1 print(x) # 使用迴圈更替idx,並依序執行程式碼。 for idx in range(2, len_of_num): x[idx] = x[idx - 1] + x[idx - 2] print(x) ``` ## 第二節:迴圈(3) * 上述程式碼的實際運作,其實是依序重複執行迴圈內的程式碼 * 因此在第一個迴圈中Python其實是做了以下的事情。 * 在第一圈時,變數idx被指定為以range()所產生的第一個內容「2」。 ```python= idx = 2 x[idx] = x[idx - 1] + x[idx - 2] ``` * 第二迴圈則是令idx為range中的第二個數字3。 ```python= idx = 3 x[idx] = x[idx - 1] + x[idx - 2] ``` * 依此類推,到最後一個迴圈時則是令idx = 11。 ```python= idx = 11 x[idx] = x[idx - 1] + x[idx - 2] ``` * 同學們是否覺得迴圈其實很簡單呢? ## 第二節:迴圈(4) * 迴圈所指派的變數不見得必須是數字,例如也可以是文本,下面是一個合併迴圈與判斷的範例。 * 我們可以讓Python告訴我們這些單字有哪些英文字母的字數大於等於5。 ```python= words = ['cat', 'window', 'defenestrate'] for w in words: if len(w) >= 5: print(w, len(w)) ``` * 以下範例也是一種常用來索引內容物以及處理資料的演算法。 ```python= a = ['Mary', 'had', 'a', 'little', 'lamb'] for i in range(len(a)): print(i, a[i]) ``` ## 練習3:迴圈與條件判斷的組合 * 現在我們已經有更好的方式可以回答本堂課練習1中的問題3。 ```python= x = [16, 6, 13, 1, 3, 4, 14, 11, 11, 10, 9, 4, 6, 3, 9, 4, 2, 14, 17, 13, 16, 9, 6, 16, 1, 1, 9, 5, 8, 6, 14, 11, 13, 17, 3, 9, 20, 9, 11, 4, 17, 8, 3, 16, 8, 4, 8, 9, 20, 14, 14, 5, 14, 6, 4, 6, 6, 13, 1, 9, 6, 14, 16, 9, 20, 16, 9, 13, 13, 4, 2, 5, 8, 14, 18, 16, 16, 4, 18, 11, 18, 11, 10, 6, 5, 17, 9, 11, 13, 20, 8, 8, 16, 9, 13, 4, 3, 17, 16, 9, 6, 8, 3, 8, 2, 20, 11, 14, 16, 8, 11, 13, 1, 4, 20, 16, 17, 3, 16, 5, 20, 20, 5, 4, 5, 16, 6, 11, 10, 2, 17, 13, 18, 2, 13, 2, 9, 2, 9, 13, 16, 8, 5, 11, 6, 18, 9, 9, 5, 11, 1, 8, 5, 2, 9, 16, 1, 3, 5, 6, 2, 1, 9, 16, 20, 6, 4, 6, 8, 3, 5, 13, 17, 6, 1, 6, 4, 9, 6, 6, 5, 5, 5, 17, 8, 13] ``` * 問題1:這個數列中缺少了1至20中的哪些數字?請利用迴圈與判斷。 <details> <summary>解答</summary> ```python= uni_x = set(x) for idx in list(range(1, 21)): if idx not in uni_x: print("缺少了", idx) ``` </details> * 費波納奇數列是起始數列為1、1,之後每個數為前兩個數之和。現在,我們來創造一個NDMC數列,其定義是起始數列為1、1,之後第三個數字(奇數)為前兩個相加,第四個數字(偶數)為前兩個數字相乘,第五個數字(奇數)為前兩個相加,依此類推 ```python= # 創建長度為10,元素皆為0的list。 len_of_num = 10 x = [0] * len_of_num # 將前兩個數字皆替換成1。 x[0:2] = 1, 1 print(x) ``` * 問題2:請用迴圈功能完成它(小心奇偶數順序時,要做的動作不同,請同學思考如何利用條件判斷來完成這個問題)。 <details> <summary>解答</summary> - 這題其實有很多解法,解法一相對直觀。 ```python= for idx in range(2, len_of_num): if idx % 2 == 0: x[idx] = x[idx - 1] + x[idx - 2] else: x[idx] = x[idx - 1] * x[idx - 2] print(x) ``` - 解法二相對不直觀,但也是一種思考模式。 ```python= for idx in range(1, int(len_of_num/2)): x[2*idx] = x[2*idx - 1] + x[2*idx - 2] x[2*idx+1] = x[2*idx] * x[2*idx - 1] print(x) ``` </details> ## 第三節:巢狀迴圈(1) 迴圈的美妙之處在於能夠大量且依序運算,我們將透過迴圈進行更複雜的組合任務:巢狀迴圈(Nested for-loop)。 * 現在讓我們想辦法列出2到6內所有的「質數」。 * 何謂質數?質數為找不到比自己更小的可整除除數,如5以下的數字為2、3、4,而5無法被這些數字整除。 * 現在讓我們思考該如何回答這個的問題。 ## 第三節:巢狀迴圈(2) * 我們先產生一個變數x儲存2至6的所有數字,再創建answer變數表示變數x中相對應的元素是否為質數,而answer皆預設為True ```python= x = list(range(2, 7)) answer = [True] * len(x) ``` * 讓我們一步一步來思考,可以先從3開始。 ```python= # 對3進行檢測(x物件中的第2個數字) if x[1] % x[0] == 0: answer[1] = False # 對4進行檢測(x物件中的第3個數字) if x[2] % x[0] == 0: answer[2] = False if x[2] % x[1] == 0: answer[2] = False # 對5進行檢測(x物件中的第4個數字) if x[3] % x[0] == 0: answer[3] = False if x[3] % x[1] == 0: answer[3] = False if x[3] % x[2] == 0: answer[3] = False # 對6進行檢測(x物件中的第5個數字) if x[4] % x[0] == 0: answer[4] = False if x[4] % x[1] == 0: answer[4] = False if x[4] % x[2] == 0: answer[4] = False if x[4] % x[3] == 0: answer[4] = False ``` * 這樣我們可以透過answer來索引x,得到6以下的質數: ```python= for idx in range(len(x)): if answer[idx]: print(x[idx]) ``` ## 第三節:巢狀迴圈(3) * 聰明的你是不是已經發現某些規律,我們可以先利用變數取代部分索引的數字。 ```python= # 宣告變數 x = list(range(2, 7)) answer = [True] * len(x) i = 1 # 對3進行檢測(x物件中的第2個數字) if x[i] % x[0] == 0: answer[i] = False i = 2 # 對4進行檢測(x物件中的第3個數字) if x[i] % x[0] == 0: answer[i] = False if x[i] % x[1] == 0: answer[i] = False i = 3 # 對5進行檢測(x物件中的第4個數字) if x[i] % x[0] == 0: answer[i] = False if x[i] % x[1] == 0: answer[i] = False if x[i] % x[2] == 0: answer[i] = False i = 4 # 對6進行檢測(x物件中的第5個數字) if x[i] % x[0] == 0: answer[i] = False if x[i] % x[1] == 0: answer[i] = False if x[i] % x[2] == 0: answer[i] = False if x[i] % x[3] == 0: answer[i] = False ``` * 可以發現對於每個數字,檢查是否整除的程式碼行數不同,而越後面的數字行數越多。 ## 第三節:巢狀迴圈(4) * 這時同學們是不是其實已經想到,我們可以再撰寫一個內圈(inner loop)。 * 我們可以先這樣理解,將內圈以變數j替代。 ```python= # 宣告變數 x = list(range(2, 7)) answer = [True] * len(x) # 外圈:對3進行檢測(x物件中的第2個數字) i = 1 # 內圈 j = 0 if x[i] % x[j] == 0: answer[i] = False # 外圈:對4進行檢測(x物件中的第3個數字) i = 2 # 內圈 j = 0 if x[i] % x[j] == 0: answer[i] = False j = 1 if x[i] % x[j] == 0: answer[i] = False # 外圈:對5進行檢測(x物件中的第4個數字) i = 3 # 內圈 j = 0 if x[i] % x[j] == 0: answer[i] = False j = 1 if x[i] % x[j] == 0: answer[i] = False j = 2 if x[i] % x[j] == 0: answer[i] = False # 外圈:對6進行檢測(x物件中的第5個數字) i = 4 # 內圈 j = 0 if x[i] % x[j] == 0: answer[i] = False j = 1 if x[i] % x[j] == 0: answer[i] = False j = 2 if x[i] % x[j] == 0: answer[i] = False j = 3 if x[i] % x[j] == 0: answer[i] = False ``` * 讓我們先關注於6的部分,似乎可以將這些程式碼合成一個迴圈。 ```python= # 外圈:對6進行檢測(x物件中的第5個數字) i = 4 # 內圈 for j in range(4): if x[i] % x[j] == 0: answer[i] = False ``` * 找到內圈的規律後,我們將其推廣到外圈(outer loop),並且對於每個j剛好到i-1。 ```python= # 宣告變數 x = list(range(2, 7)) answer = [True] * len(x) # 外圈:對3進行檢測(x物件中的第2個數字) i = 1 # 內圈 for j in range(i): if x[i] % x[j] == 0: answer[i] = False # 外圈:對4進行檢測(x物件中的第3個數字) i = 2 # 內圈 for j in range(i): if x[i] % x[j] == 0: answer[i] = False # 外圈:對5進行檢測(x物件中的第4個數字) i = 3 # 內圈 for j in range(i): if x[i] % x[j] == 0: answer[i] = False # 外圈:對6進行檢測(x物件中的第5個數字) i = 4 # 內圈 for j in range(i): if x[i] % x[j] == 0: answer[i] = False ``` ## 練習4:巢狀迴圈與條件判斷的組合 * 同學們應該已經有能力完成接下來的步驟,透過巢狀迴圈列出2到6內所有的「質數」,並有能力推廣到更多的數目。 * 問題1:請試著理解剛剛的每一個過程,並撰寫巢狀迴圈找出100以下的質數有哪些。 <details> <summary>解答</summary> - 同學們其實可以發現range(0)是不會進入內圈的,所以下列的程式碼會看起來更簡潔。 ```python= num_to_slove = 101 # 宣告變數 x = list(range(2, num_to_slove)) answer = [True] * len(x) for i in range(len(x)): for j in range(i): if x[i] % x[j] == 0: answer[i] = False for idx in range(len(x)): if answer[idx]: print(x[idx]) ``` </details> * 問題2:事實上質數可以再更精確的定義為找不到比自己更小的可整除的「質數」,如5以下的「質數」為2、3,因此在檢查5的時候我們其實不需要檢查4這個數字。 <details> <summary>解答</summary> - 除此之外,「break」語句能夠提早終止迴圈。 ```python= num_to_slove = 101 # 宣告變數 x = list(range(2, num_to_slove)) answer = [True] * len(x) for i in range(len(x)): for j in range(i): if answer[j]: if x[i] % x[j] == 0: answer[i] = False break for idx in range(len(x)): if answer[idx]: print(x[idx]) ``` </details> ## 總結 * 同學們請回去務必練習並熟悉這些相關的程式語法。 * 資料型態轉換。 * 條件判斷式。 * 迴圈。 * 這堂課主要在教導如何撰寫條件判斷式與迴圈,同學們應該已有能力用Python處理許多任務。 * 熟悉迴圈指令將能夠讓電腦幫你處理許多常規的重複工作!