iT邦幫忙

9

【Python 超入門】(8) break/continue 邏輯- 造謠者向其它求職者說:「我已經拿到這份工作了,你們可以回家了」

大家好,我是「心原一馬」,內心原來一心喜歡打程式碼。
上一篇中,我們教大家如何使用for/while迴圈,
for迴圈可以遍歷列表,
而while迴圈可以在條件不滿足前一直執行,
但有時候,我們也會有需要提早跳出迴圈的情境,
我們可以用下面這個故事來理解…

我的專長是造謠

有一個人去應徵一份工作,
在履歷上寫著「專長: 造謠。」
面試官看了覺得很新奇,跟那人說:「那你造一次謠給我們看看。」
只見那個人走出面試會議室,
跟其它排隊等候面試的求職者說:「我已經錄取這份工作了,你們可以回家了。」

好的,那這段故事在比喻什麼呢?
其實啊,會需要提早跳出迴圈的情況就像公司徵才過程一樣,
假設公司職缺只開一個,
一開始主管會需要面試所有應徵者,
但一旦主管確信他已經找到非常適合的人選,
那麼後面的人可能就不必再通知面試了,
這時徵才可能就會提早結束。

break指令- 提早結束迴圈

在多數程式語言中,提早結束迴圈的指令是break
我們試著寫出這段邏輯看看:
(請注意,以下只是表達一段程式邏輯,並不是真正可執行的程式碼哦~)

for 求職者 in 求職者名單:
    面試求職者
    if 找到適合的人選:
        break

又或者,你是非常優秀的人才,
你報名參加多間心目中好公司的面試,
那麼你可能決定如果有公司錄取自己了,
後面幾家公司的面試就不去了。
(這邊不考慮等候錄取通知和面試時間可能重疊的情境,假設都是一家公司面完才去下一家)
那麼可以用以下的邏輯表達:

for 公司 in 心目中好公司名單:
    參加公司面試
    if 被公司錄取:
        break

對了,發現了嗎?
break通常會跟if搭配使用,
因為我們通常是滿足某個條件才會提早跳出迴圈,
如果你寫:

for 公司 in 心目中好公司名單:
    參加公司面試
    break

這段邏輯沒有跟if搭配,
表示不論如何你只會參加第一間公司面試,
後面公司都不去了。
所以我們幾乎不會單獨使用break指令。

來看看幾個可以執行的程式碼例子吧:

範例1: 我要錄取第一個英文名字開頭為'D'的人

(此範例只是為了方便舉例,請勿當真)
假設我們用candidates 變數表示等候應徵的求職者,
而主管想要錄取英文名字開頭為'D'的人選,一旦找到人選面試流程就結束。
程式如下:

candidates = ['Alice', 'Bob', 'Cindy', 'Daisy', 'Eve', 'Fairy', 'David'] 
for candidate in candidates:
    print('輪到 ' +candidate+ ' 面試')
    if candidate[0]=='D': #如果字串的第一個字為'D'
        print('恭喜 ' +candidate+ ' 錄取')
        break

結果:
輪到 Alice 面試
輪到 Bob 面試
輪到 Cindy 面試
輪到 Daisy 面試
恭喜 Daisy 錄取

continue指令- 你被跳過了

程式語言中,還有一個跟break相似的指令,continue
那這兩個指令有什麼差別呢?
我們繼續用面試的例子來說明。
如果for像面試官一樣,
對名單上的所有人進行面試,
那麼,

  • break指令是直接跳出整個面試流程,相當於後面的人都不必面試了
  • continue指令則是跳過該應徵者,繼續進行後面的面試

寫成邏輯就像這樣:

for 求職者 in 求職者名單:
    面試求職者
    if 求職者條件不足:
        continue
    (註: 如果求職者沒有被continue指令跳過) 該求職者被納入考慮名單中

再跟break邏輯比較一下:

for 求職者 in 求職者名單:
    面試求職者
    if 找到適合的人選:
        break

雖然breakcontinue都有跳過的意思,
break是直接跳出整個迴圈,
continue只是跳過當次迴圈中接下來的指令,迴圈繼續執行。

範例2: 合適的人選進入第二關

範例1中,只憑應徵者的名字來決定是否錄取,
給人有偏見的感覺,
因此,主管決定改用一個較公正的方法來徵才:
先讓他們參加第一階段的考試,80分以上者可以進入第二關。
這次我們用candidates 變數表示等候應徵的求職者,
用scores 變數表示他們對應的第一階段的分數。
(已知有7個應徵者)
程式如下:

candidates = ['Alice', 'Bob', 'Cindy', 'Daisy', 'Eve', 'Fairy', 'David'] 
scores = [74, 83, 73, 91, 80, 76, 89]
for i in range(7): #遍歷數字0,1,2,3,4,5,6
    print(candidates[i]+ ' 的分數為:', scores[i])
    if scores[i]<80: #如果求職者分數小於80分,跳過他
        continue
    print('恭喜 ' +candidates[i]+ ' 進入第二關面試')

結果:
Alice 的分數為: 74
Bob 的分數為: 83
恭喜 Bob 進入第二關面試
Cindy 的分數為: 73
Daisy 的分數為: 91
恭喜 Daisy 進入第二關面試
Eve 的分數為: 80
恭喜 Eve 進入第二關面試
Fairy 的分數為: 76
David 的分數為: 89
恭喜 David 進入第二關面試

舉一反三- break應用於while迴圈中

範例3: 韓信點兵- 三三數之剩二,五五數之剩三,七七數之剩二

「韓信點兵」是經典的數學問題,題意是說
韓信讓他的士兵三個排成一列會餘2個;
士兵每五個排成一列會餘3個;
士兵每七個排成一列會餘2個。
試問: 韓信最少有幾個士兵?

在數學上,有「中國剩餘定理」可以解這個問題,
如果我們不知道這個定理的話,
其實也是可以用程式暴力搜索解開的哦~

想法如下: 從正整數1開始檢查,
如果這個數字滿足「除以3餘2,除以5餘3,除以7餘2」條件,
就把這個數字印出來並跳出迴圈,
否則繼續檢查下一個正整數。
程式如下:

num = 1 #設定要檢查的數字的初始值
while True: # while True除非接收到break指令,否則迴圈永遠不會停下來
    if num%3 ==2 and num%5==3 and num%7==2: #取餘數的算術運算子是%
        #num本身是整數,必須用str()函數把num轉換成字串,才可以串接字串
        print('韓信最少有'+str(num)+'個士兵')
        break
    num+=1 

結果: 韓信最少有23個士兵
實際手算一下,23真的滿足「除以3餘2,除以5餘3,除以7餘2」條件。

課後練習-千軍萬馬

又到了課後練習時間啦~
在範例三中,已知目測韓信的士兵大約有500~1000人左右,
那麼韓信可能有多少士兵呢?
請嘗試修改範例3的程式,印出所有可能的結果。
print的部分請改成

print('韓信可能有'+str(num)+'個士兵')

歡迎在留言區留下你的答案交流討論哦~
進階思考: 你能不能只用while迴圈和if判斷式,而不用break指令完成呢?

【超進階版】首次有讓高手練習的問題來囉~ (本問題適合對python足夠熟悉者作答,新手可直接略過此部分。)考慮這邊是新手教學區,欲作答討論或詢問答案可直接私訊,並註記是在【python 超入門】(8)文章中看到的問題,本馬會跟您討論。
(1)給python好手的挑戰: 用任何你知道的python語法都行,你能否在三行以內解開呢?
(2)給python高高手的超進階挑戰: 你能否只用一行程式完成呢?
(注意你的答案中必須包括print('韓信可能有'+str(num)+'個士兵')以印出結果)


4
dylanliu
iT邦新手 5 級 ‧ 2019-07-05 17:44:01
num = 500 #設定要檢查的數字的初始值
while 500<= num <=1000: # while True除非接收到break指令,否則迴圈永遠不會停下來
   if num%3 ==2 and num%5==3 and num%7==2: #取餘數的算術運算子是%
      #num本身是整數,必須用str()函數把num轉換成字串,才可以串接字串
      print('韓信可能有'+str(num)+'個士兵')
   num+=1     
心原一馬 iT邦研究生 5 級 ‧ 2019-07-05 21:52:08 檢舉

Bingo~ 恭喜答對,成功不用break語法解開了,讚讚~

1
harutsuki
iT邦新手 5 級 ‧ 2019-07-08 18:22:32
for num in range(500, 1000):
    if num%3==2 and num%5==3 and num%7==2:
        print('韓信最少有'+str(num)+'個士兵')
心原一馬 iT邦研究生 5 級 ‧ 2019-07-09 10:51:15 檢舉

Bingo~ 這個也是正解,用for迴圈加range函數確實更簡潔呢~

0
harutsuki
iT邦新手 5 級 ‧ 2019-07-24 17:37:50
num_list = [f'韓信最少有{i}個士兵' for i in range(500, 1000) if i%3==2 and i%5==3 and i%7==2]
print(*num_list, sep="\n")  
0
harutsuki
iT邦新手 5 級 ‧ 2019-07-24 17:39:40
print("\n".join([f'韓信最少有{i}個士兵' for i in range(500, 1000) if i%3==2 and i%5==3 and i%7==2]))
2
harutsuki
iT邦新手 5 級 ‧ 2019-07-24 17:45:56
[print(f'韓信最少有{i}個士兵') for i in range(500, 1000) if i%3==2 and i%5==3 and i%7==2]
心原一馬 iT邦研究生 5 級 ‧ 2019-07-24 18:22:02 檢舉

哇~ 高手是你~ 你的三個解答,把小馬心目中的精簡解答都寫出來了呢~

1
medivh0102
iT邦新手 5 級 ‧ 2020-03-06 10:06:24

想了一整個晚上想破頭
終於在剛剛得到解答了! 答案如下:
num = 500
while 500<=num<=1000:
if num%3 ==2 and num%5==3 and num%7==2:
print('韓信可能有'+str(num)+'個士兵')
num+=1

這次課程對我這菜鳥有難度..昨天一度萌生是不是沒天份的念頭,最後把4.6.7章反覆拿出來一個一個看,但終究不知道在「有break」的前提下程式碼要怎麼打,反而是把稍微進階的答案寫出來了....
但是經過這次問題測驗也充分了解自己的問題,謝謝一馬哥!下面也麻煩一馬哥賜教:

1.我最初卡在的問題點在於「迴圈會只顯示一次[韓信最少有548個士兵]就不再顯示,那時候我是在 if num%3 ==2 and num%5==3 and num%7==2:這行後面新增 and 500<=num<=1000,請問這個 邏輯是哪裡錯了呢? 還有為什麼改成while 500<=num<=1000 之後,系統會正確的一行一行的 顯示出我要的數字了呢?

2.「#num本身是整數,必須用str()函數把num轉換成字串,才可以串接字串」:
我自己是這樣解釋的:因為num本身是"數字",必須要用『str()函數』將他帶入括弧已把他轉換成 字串(文字),才可以在print裡面讓他前後都連結著文字。 <-請問這樣解釋可以嗎?
這是因為這個變數有經過計算,隨時都會更動,跟直接key in一個固定的數字進去不一樣,所以要 用str()是更改 是這個意思嗎?

3.在break語法練習中:
candidates = ['Alice', 'Bob', 'Cindy', 'Daisy', 'Eve', 'Fairy', 'David']
我自己打的時候忘記是列表,所以將中括號打成小括號,結果程式一樣可以正常進行,這是因為如同一馬哥您所說的「只要對稱就可以」的緣故嗎?

不好意思這次問題有點多 煩請賜教!

看更多先前的回應...收起先前的回應...
心原一馬 iT邦研究生 5 級 ‧ 2020-03-06 12:06:37 檢舉

您好:
其實小馬覺得你學程式算很有天分了,
能夠知道自己哪裡不懂,
能夠思考後學著發問,
算是非常好的

而且你的學習精神算是很好的,
能夠跟著實作,
嘗試自己先練習過而不急於看解答

一開始會覺得有難度是正常現象,
為何園區的工程師值年薪百萬呢?
表示這個領域確實有它深的地方,
無法一步登天

小馬覺得學程式需要「熟能生巧」吧,愈常練習,
接觸的多,看的例子多了,
則較容易順利寫出想要的程式碼,
加油哦~

再來回答你的問題:

  1. 首先建議你打程式碼的時候,可以用「```」(在鍵盤左上角1左邊的符號)符號把程式碼包起來,對於讀者會較容易閱讀

譬如你的這段程式碼
num = 500
while 500<=num<=1000:
if num%3 ==2 and num%5==3 and num%7==2:
print('韓信可能有'+str(num)+'個士兵')
num+=1

可以打成

num = 500
while 500<=num<=1000:
    if num%3 ==2 and num%5==3 and num%7==2:
        print('韓信可能有'+str(num)+'個士兵')
    num+=1

截圖給你看在文字編輯視窗打的樣子:
https://ithelp.ithome.com.tw/upload/images/20200306/20117114oJn6Wz9fvj.png

用這樣的方式,小馬才能知道你確切的程式碼是怎麼打的而幫你解惑哦

  1. 你說的大致沒錯。「加法」需要同類型才能相加,
    以日常生活的例子來說,
    「1隻貓」+「1隻貓」=「2隻貓」,
    「1隻狗」+「1隻狗」=「2隻狗」,
    但「1隻貓」+「1隻狗」則無法直接相加

程式也類似:
<字串>'1'+'1'等於'11'
<數字>1+1等於2
但不能直接把字串與數字相加,
故需要用str(num)把數字轉型為字串

  1. 若將中括號誤打為小括號,如candidates = ('Alice', 'Bob', 'Cindy', 'Daisy', 'Eve', 'Fairy', 'David'),則candidates不是列表,它是另一種資料型態,叫做「元組」(tuple)。「列表」與「元組」非常類似,至於初學者暫可不必探究差別,先學習用「列表」即可

https://ithelp.ithome.com.tw/upload/images/20200306/2012522522YVoygzcg.png]
一馬哥不好意思造成您閱讀上的不便
重新附上程式碼如附圖
如果打成這樣的話只會出現一次 548個士兵 就沒有下文了
請問一馬哥造成這樣的邏輯是甚麼呢?為什麼不會像標準答案那樣跑到968個呢?

心原一馬 iT邦研究生 5 級 ‧ 2020-03-06 22:54:48 檢舉

您好:

可再細細品味break的涵義,
若把for, while迴圈比喻成面試招募人才,
break的效果就相當於直接結束面試(跳出迴圈)

依你的寫法,num%3 ==2 and num%5==3 and num%7==2的條件一旦成立時,就直接跳出迴圈,
也就只會印出一次囉

如果需要用break來完成此題,
你的while迴圈裡面應該要有兩個if判斷,
第一個是if num%3 ==2 and num%5==3 and num%7==2
印出結果,
第二個是if用來判斷結束迴圈的時機(當num大於1000時跳出),
你可以再想想如果一定要用break怎麼寫,
若明天還是想不出,小馬可公佈答案,
加油~

num = 500
while True: 
    if num%3 ==2 and num%5==3 and num%7==2: 
     if num >=1000:
      break
     print('韓信最少有'+str(num)+'個士兵')
    num+=1 

謝謝一馬哥教導有方 這麼簡單的答案我居然想半天...OTL

心原一馬 iT邦研究生 5 級 ‧ 2020-03-06 23:28:31 檢舉

好的,恭喜有想出來,
不過你的「`」符號應該有打錯(要有出現黑底程式碼區塊才算成功),
建議你直接複製我的「`」符號試試?

是要打全形的才可以XD
我都傻傻的按半形

心原一馬 iT邦研究生 5 級 ‧ 2020-03-06 23:42:57 檢舉

應該是半形的呀?不過恭喜你成功試出程式碼區塊的效果了
/images/emoticon/emoticon42.gif

roychuang iT邦新手 5 級 ‧ 2021-06-07 10:19:57 檢舉
num = 500
while 500<=num<=1000:
    if num%3 ==2 and num%5==3 and num%7==2:
    print('韓信可能有'+str(num)+'個士兵')
num+=1
1
eric19980227
iT邦新手 5 級 ‧ 2020-04-16 00:04:06

一馬哥你好
最近才開始學習Python而且程式的基礎也沒有很好QQ,看了一馬哥的文章後才慢慢有輪廓,今天想了很久還是不知道這個哪裡的邏輯不對,還請一馬哥不吝賜教,謝謝
people=1
while True:
people=people+1
while 1000>=people>=500:
if people%3==2 and people%5==3 and people%7==2:
print("韓信有"+str(people)+"位士兵")
break

心原一馬 iT邦研究生 5 級 ‧ 2020-04-16 08:56:04 檢舉

嗨,你好:
謝謝你的發問,
不過方便把你的程式碼包成「程式碼區塊」嗎?
這樣沒有縮排(譬如: 寫在while迴圈裡的程式換行要空四格)的程式會不容易閱讀(可能因縮排的不同程式碼意思也不同),
謝謝您~
給你iT邦的格式說明做為參考,
iT邦的Markdown格式說明

一馬哥不好意思,感謝感謝

people=1
while True:
    people=people+1
    while 1000>=people>=500:
        if people%3==2 and people%5==3 and people%7==2:
            print("韓信有"+str(people)+"位士兵")
    break  
心原一馬 iT邦研究生 5 級 ‧ 2020-04-16 11:27:39 檢舉

好的,謝謝你,這樣程式碼清楚多了,
while迴圈的意思是說「當條件成立,就會不斷執行裡面的內容」,
所以撰寫while迴圈的一個要點是判斷程式碼有沒有辦法離開迴圈,
否則就會卡在while迴圈裡出不去

你的程式有兩點邏輯需要修正:
一是break的位置寫的不對,
你的程式

while True:
    people=people+1
    …
    break  

會在剛進入while True迴圈時,
就執行break而跳出while迴圈,
因此break幾乎99.999%要寫在if語句裡,
不能單獨使用哦

第二點,假設把break拿掉好了,
以你的程式來說,
你的while 1000>=people>=500:裡面,
當people的數量介於500~1000之間的時便會執行這個迴圈,
但是當進入這個迴圈後,
people的數量就不會改變了,
(你的「people=people+1」寫在while 1000>=people>=500:這個迴圈的外面,
所以你的程式會執行到people=500時,
就會一直卡在while 1000>=people>=500:裡面而進入無窮迴圈)

建議此題不要寫雙重迴圈(while裡面有while),
正確寫法可參考樓上留言,
或自己再寫寫看,
如果真的想不出來可再發問哦 ^^

祝 學習順利~

我要留言

立即登入留言