那麼呢,就像我們剛剛講過的,你這個有兩個 while,然後你裡面有 break 的時候只會跳出 一層迴圈,如此這般,如此那般,那個就是 nested loop,就是巢狀 迴圈,對吧?那就像巢狀的選擇一樣,巢狀的迴圈 也是非常地常用,你想要解稍微有點規模的問題的話,一定會用到巢狀迴圈。 所以呢我們現在要來學學 loop 它們要怎麼樣可以被 nested,那 nested 以後我們就會 有外迴圈,內迴圈,超內迴圈等等的,那它通常可以幫我們做很多事情。 很多的時候,我們會發現 nested loop 也不是一定需要,但它們的確是有幫助。 特別是我們在處理一些所謂的 multi-dimensional 的問題的時候, 那什麼時候呢?來看幾個例子吧。 比如說 我今天想要請你寫一個 program,它可以印出在 xy 平面,也就是 你的二維平面上面的一些整數點,大概是像左邊寫的這個樣子。 請你印出 (1,1), (1,2), (1,3),然後換行 (2,1), (2,2), (2,3),然後以此類推。 那假設是這樣子好了,我就想看到這個 3 乘 3 的這張表的話,最簡單的做法 就是像框框里寫的這樣。 我啊,我知道,我呢最終一定就是做一個 print 這個 print 基本上就是要印左括弧 印一個數字,一個逗點和空格,然後一個數字 然後右括弧,主要就是要做這件事情。 這件事情很明顯地我要做九次, 我怎麼知道它是九次呢?因為是三乘三,而我每一次做得時候的值 都要視情況改變。 我呢一開始要印 (1,1),然後 1 要變成 2,2 要變成 3, 但在那之後,1 就要變成 2,然後呢 3 還要變回 1, 所以想想好像蠻複雜的。 不過你看一下這個例子的話, 其實很簡單。 我最終就是需要兩個變數,我呢第一個變數叫做 x,它的值是什麼? 就是 1 到 3 嘛,所以這個 range 就是 1 到 3,然后呢我在這裡面 我的 range 我傳 3 進來的時候,它給我的是 0, 1, 2 哦, 不是 1, 2, 3,所以我要先把 x 變大一單位,讓我的 x 變成是 1 或 2 或 3。 好,現在在外迴圈裡面我的 x 已經是 1 了,我接著進入內迴圈。 內迴圈給我一個 y,又是 0, 1, 2,所以我把 y 加 1,變成 1, 2, 3。 好,現在內迴圈的 y 是 1 了,我呢就這樣子 print 出 (1,1) 這個向量。 然後我呢,就結束了這個迴圈,於是我 就跑出內迴圈的第二圈,y 變成 2,於是我就印出 (1,2) 再一圈內迴圈印出 (1,3),再一圈內迴圈,沒有再一圈 了,因為 y 就是 0, 1, 2,然後印出 1, 2, 3 而已,這個時候內迴圈結束。 跑回去外迴圈 x 變成 2,然後以此類推,以此類推。 那我們在這裡做了這些 print 的 動作啊,大家可以看到,這裡有一個什麼都沒做的 print,它 基本上就是在 print 換行的這件事情。 因為我們這裡有一個 print,所以在這裡它才會做一個換行,那另外這裡有一個 end 這是什麼啊?這個 end 的這個參數,在這個 print 裡面 它做得事情是說呢,請你不要換到新的一行 請你不要換到新的一行,相反的,請你插入一個空格, 插入一個空格。 這樣,不然的話我們就會看到 如果你這裡不寫這個 end,我們就會看到所有的數字被印成九行,而不是三行, 這樣子。 好,那我們來試一下。 今天我們先執行看看,印出來的感覺很棒。 好,那如果我們把這個 print 拿掉,結果會怎麼樣呢?就會變成都在同一行,對吧? 所以你就知道,我們的確是需要每跑完一次內迴圈,印出由左到右 三對數字了以後,就要來換行一下,就是這個 print。 那另外,如果我們 把這個拿掉,那會怎麼樣呢?就會印出由上到下九行, 而不是三乘三,所以你確實需要在這裡註明,當我的 print 的動作結束的時候,end 的符號不要換行, 而是要空白。 那你可以看得出來,這個空白鍵其實你是可以選的,比如說我把它 拿掉,拿掉的話會怎麼樣?印出來的東西這裡就會變得很擠,就不會有一個空格。 或者是我說,那不然我換行好了,換行可以嗎?可以,就會變成跟你沒寫是一樣的。 也就是說 print 的預設的 end 的符號就是換行,所以我們現在需要空格,就給它 一個空格。 那麼你也可以試試看,我們如果在這裡,我們不要寫 range 3,我們寫 range (1, 4) 可以嗎?我們這裡寫 range (1, 4),然後我們把這個 y+=1、 x+=1 刪掉,可以嗎? 這樣會不會也 OK 呢?當然也 OK,因為你知道你在幹嗎嘛,那這樣子自然就可以理解這個程式為什麼對 或者是錯。 那剛剛這個例子啊 同樣地,你只寫一層迴圈也可以做,你就在那邊數 x 跟 y 誰要變大誰要變小之類的,就可以了。 但肯定用 nested loop 是方便的多。 那我們再看另外 一個例子。 這個例子呢,就是大家從小到大 都印象深刻的,所謂的 multiplication table,就是九九乘法表啦。 那我們這裡為了版面簡單起見,我們就來個五五乘法表就好了,所以 x 是 1 到 5, y 是 1 到 5,每一次請你幫我印 x 乘上 y 等於若干若干,那一樣,裡面不要換行,出來以後再換行。 好,我們很快地試一下。 印出來的結果大概長得像這樣子,看起來還不錯,對吧?1 乘以 1 是 1,1 乘以 2 是 2, 1 乘以 3 是 3,1 乘以 4 是 4,2 乘以 3 是 6,3 乘以 4 是 12,4 乘以 4 是 16,等等。 因為我們的 range 是 1 到 5 嘛,所以其實是四四乘法表,而不是五五乘法表了。 那你可以看到,我們一共做了十六次裡面的這個 print 而每一次呢,這個 x 跟 y 的值都會略作改變、 略作改變。 當 x 的值 固定在 1 的時候,y 的值會先是 1,然後是 2,然後是 3,然後是 4, 這樣我們就印出了四個運算的結果了。 接著我們會換行,因為我們內迴圈結束, 所以我們會換行,換行完了跳回第一行,x 的值變成 2,然後再把同樣的 事情再重做一次,大概就是這個兩層迴圈在做的事情啦。 所以呢,你可以想想,這裡有幾個延伸問題。 首先就是 lower bound 跟 upper bound,如果你想要不要讓它們被寫死,在這邊是 1 到 5,而是有彈性 讓使用者可以輸入的話,那要怎麼做呢?也很簡單對吧? 前面來幾個 a 呀 b 呀 l 呀 h 呀之類的變數, 然後你讓使用者輸入,然後呢你把它們傳成整數 有了 a b 了以後呢,把這個地方換掉就可以了,請大家自己試試看。 那另外,我們今天在剛剛 print out 的時候會發現這個 長得稍微有一點點不美觀,大概是像這樣,就是這裡沒對齊吧,所以搞得就是後面有一點丑。 那這件事情要怎麼樣把它們放在同一個這個 比如說把它們依照欄位對齊呢?欸,這個問題問得倒好,答案是不方便。 答案是我們今天沒有要教你怎麼做,大家如果想要的話,因為你知道乘出來會是多少嘛, 所以你可以根據乘出來的數字,以及你最大可能會乘出多大的數字,來幫它塞一些空白, 所以也就是說你這個 print 的 statement 要加入一些 if else 才可以做。 好,那這件事情 做是做得到,那因為很 tedious 我們就不教你了,那事實上也沒有那麼計較的必要, 如果你真心需要印出來的結果很美觀的話,你大概不會寫文字界面的程式 你會寫圖形界面,你會寫網頁,你會寫 app,你不會堅持要在這個黑白畫面上 做排版,OK。 所以呢,要排版我們就會去做視窗,做 app,做網頁等等。 在現在的黑白環境下,我們基本上只要能求運算正確有效, 有效率,程式碼好維護,那這個才是我們現在這個階段的重點啦。