--- disqus: ncyubrdecoinfo --- # R 的流程控制 很多生物或生態背景的人看到「程式設計」都會有點恐懼,其實程式設計並不難,基本上就是了解語法及邏輯。在這節我們會用簡單的例子來介紹 R 的程式設計,尤其是流程控制(flow control)這部份。相信許多人都會畫簡易的流程圖,這部份的流程控制就是把流程圖轉換成文字來告訴 R 該怎麼執行。流程控制在程式語言中有個專有名詞稱為「控制結構(control structure)」,通常在一般的程式語言中,有循序(sequence)、選擇(selection)以及重複(repetition)三種類別。「循序」就是由上至下一行一行的依照順序執行,我們在寫 R 程式碼時大部分都是循序的執行;「選擇」則是有許多不同的條件,如果符合條件的話,就會依照條件下來執行;「重複」字面上來看就是不斷地重複執行某些工作。 我們用生活中的例子來說來協助理解,例如使用洗衣機洗衣服,在 R 程式設計中該怎麼用控制結構呢? 控制結構: > 1. 洗衣機有插電嗎?<br/> > 有:進行步驟 2 <br/> > 無:插上插頭後,進行步驟 2 <br/> > 2. 放髒衣服進洗衣槽 在 R 的流程控制中,即使是像洗衣機插上插頭這種細節都必須要寫進去。 所以我們接下來先看一下 R 裡頭的控制結構有哪些,再分別一個一個來仔細說明。 ### 邏輯判斷 ### R 中的控制結構總覽 在 R 裡頭的控制結構總覽請參見下表,細節將會在後面的部份解釋 表 2-1. R 的控制總覽表 | R 的控制結構 | 類型 | 解釋 | 語法 | | ------------ | ----- | -------------------------- | ------------- | | if ... else | 選擇 | 如果 ... 然後 | if ( _condition_ ) _expression_ else _expression_| | ifelse | 選擇 | 如果 ... 然後 | ifelse(_testCondition_, _yes_, _no_) | | switch | 選擇 | 根據條件切換 | switch(_expression_, ...) | | for | 重複 | 變數在某序列下,重複執行 | for ( _variable_ in _sequence_) _expression_ | | while | 重複 | 根據某些條件下,重複執行 | while ( _condition_ ) _expression_ | #### 選擇:ifelse, if-else 及 switch 在選擇的控制結構中,簡單來說就是「**如果(if)**發生一件事情**然後(then)**做些什麼」,例如:**如果**今天下雨,**然後**出門你要記得帶傘。若把它翻譯成 R 可以理解的語言,我們可以這樣寫 ```R= 如果 ( 下雨了 ) { 出門記得帶傘 } ``` 注意,上面的程式碼(code)並非可以直接執行的,只是示意,我們通常稱這樣的程式碼為 虛擬程式碼([pseudocode](https://en.wikipedia.org/wiki/Pseudocode))。使用虛擬程式碼可以幫助你先將複雜的演算法(algorithm,或籠統稱為「作法」)的概念用常人比較容易懂的方式寫出來,之後就可以轉換成該語言之程式碼。 R 的語法如下: ```R= ifelse( testCondition, yes, no) ``` 如果有個變數 val 的數值,我們想判斷這個變數是否大於 10,在 R 可以寫成 ```R= ifelse( val > 10, 'Yes', 'No') ``` 如果變數 val 大於 10, R 就會顯示 "Yes",反之則是 "No" 若選擇的控制結構比較複雜,可以用大括號把 ```expression``` 包起來,如下: ```R= if ( condition ) { expression } else { expression } ``` 其中 ```condition``` 指的是判斷的條件。而 ```expression``` 則是要陳述的表示式(字面上有點難理解,不過就是諸如運算式、 印出資料等都是 ```expression```)。你也可以只寫 ```if``` 而不用加上 ```else```。若你需要做條件判斷的情形比較複雜, 即超過兩個以上的條件判斷,可以使用 ```if``` 加上 ```elseif``` ,最後再使用 ```else```來處理,例如: ```{r}= # 隨機產生一個數值 a <- rnorm(1) # if-elseif-else 選擇 if ( a > 0 ) { print("a is greater than 0") } else if ( a == 0 ) { print("a is equal to 0") } else { print("a is less than 0") } ``` #### 重複 重複執行某些動作,在 R 的語法可以使用 ```for``` 迴圈(loop)或 ```while``` 迴圈。 迴圈代表重複執行某些動作,例如我想在 R console 中印出 1, 2, 3, ... 一直到 100: ```r= # 印出 1, 2, 3 > print(1) [1] 1 > print(2) [1] 2 > print(3) [1] 3 > print(4) [1] 4 ... (以下省略) ... > print(100) [1] 100 ``` 這個時候如果每印出一個數字,就要輸入 ```print(n)```,不就要 100 行 code 才能完成嗎? 所以迴圈就可以解決這類重複執行的動作,同樣印出 1 至 100,使用 ```for``` 迴圈可以這樣做: ```R= for ( i in 1:100 ){ print(i) } ``` ```for``` 迴圈的語法如下,括號內包的是執行動作時的序列: ```R= for ( 序列 ){ 執行動作 } ``` 另外一個迴圈則是 ```while```,如果同樣印出 1 至 100 的數字,```while``` 迴圈則要寫成: ```r= # 先把 i 的起始數值設定為 1 i <- 1 while ( i <= 100 ){ # 印出 i 的數值 print(i) # 接下來設定 i' = i + 1,也就是每印完一個數字後, # i 自動加 1 i <- i + 1 } ``` 有注意到嗎?在 ```for``` 迴圈中,括號內要設定好一個序列,例如 1 至 100 (R 的語法 ```1:100```),但 ```while``` 則是限定在某個條件下,以本例來說就是 i 小於等於 100 時,R 才會重複大括號內的執行動作。如果今天寫 ```while ( 1+1 == 2 )``` 時,這個迴圈就會變成「無窮迴圈」了,R 會一直執行他到天荒地老永遠都不會停! 如果你不幸的沒寫好讓它變成無窮迴圈的話,你只要按 RStudio 的 R console 右上角的 stop 就可以停止執行,或是在非 RStudio 介面下,按 Ctrl + c 來強迫中斷執行。 ![RStudio 停止執行 R Console 內的動作](https://i.imgur.com/lkiqotW.png) ## 作業 [HW3](/09iWCsbsS9uDxObzwvXMNA) ## 上課練習 R Script ```R ## 2017-10-26 Ecoinformatics #.libPaths('~/Library/R/site-libraries/') x <- 10 # 使用 ifelse() 函式 ifelse(x <= 5, "Yes", "No") # 使用 if ... else ... if ( x <= 5 ){ print("Yes") } else { print("No") } a <- rnorm(1) # if-elseif-else 選擇 if ( a < 5 ) { print("a is less than 5") } else if ( a > 0 ) { print("a is between 0 to 5") } else { print("a is greater than 5") } # 重複 # 在 R 裡頭要代表序列的話,可以用 n:m 1:100 for ( i in 1:100 ){ print(i) } # while 迴圈 i <- 1 while ( i <= 100 ){ # 印出 i 的數值 print(i) # 接下來設定 i' = i + 1,也就是每印完一個數字後, # i 自動加 1 i <- i + 1 } while ( 1 + 1 == 2 ){ print("1+1=2, 對啊,這還用說") } ```