class: left, top, title-slide .title[ # Programming
Control Structures in R ] .author[ ### Keith VanderLinden
Calvin University ] --- # Control Structures in R Programming languages generally provide the following basic *control structures*: - Sequence - Selection - Repetition In addition, they also generally provide the ability to write new *functions*. ??? - These more advanced programming constructs are useful in more advanced data analysis. - We've been pretty much using sequence only, but the other control structures have, on occasion, been implicit. --- # Control Structures: Selection Selection statements implement “decisions” in code. .pull-left[ Traditional `if-else` Statement ```r x <- NA if (is.na(x)) { print("NA warning!") } else { print("All clear!") } ``` ``` [1] "NA warning!" ``` ] .pull-right[ `case` Function ```r x <- NaN case_when( is.nan(x) ~ "NaN warning!", is.na(x) ~ "NA warning!", TRUE ~ "All clear!" ) ``` ``` [1] "NaN warning!" ``` ] ??? - There is an `ifelse` function as well (used by necessity in the hotel dataset), but the `case_when` is more general. - We'll see an example of using the second form in the data cleansing lecture demos. --- # Control Structures: Repetition Repetition statements implement “iteration” in code. .pull-left[ Traditional `for` Loop ```r my_numbers <- c(1, -2, 3) for (x in my_numbers) { print(abs(x)) } ``` ``` [1] 1 [1] 2 [1] 3 ``` ] .pull-right[ Implicit Vector Looping ```r my_numbers <- c(1, -2, 3) abs(my_numbers) ``` ``` [1] 1 2 3 ``` Explicit Mapping Function ```r map_dbl(my_numbers, abs) ``` ``` [1] 1 2 3 ``` ] ??? - R supports traditional `for` and `while` statements, but the *implicit* looping in the vector operation and the *explicit* looping of the map operator are more common. --- # Writing Functions Functions implement procedural *abstraction*. .pull-left[ Function *Definition* ```r my_xor <- function (x, y) { (x | y) & !(x & y) } ``` ] .pull-right[ Function *Call(s)* ```r my_xor(TRUE, FALSE) ``` ``` [1] TRUE ``` ```r my_xor(TRUE, TRUE) ``` ``` [1] FALSE ``` ] ??? - The principle of *abstraction* allows us to ignore low-level details. - Here, we bundle the details of the XOR function into a function. This allows us to: - Focus on the logical analysis at hand rather than on the low-level details of XOR. - Call the XOR function many times, without repeating all the low-level details. - Function components: - Name: Choose a good one (e.g., not `xor`, which is already taken or `frodo`, which is unintelligible.) - Arguments (aka, parameters): Specify the "input" data needed to do the function's work. - Body: This is the code required to do function's work. It usually specifies a return value. --- # Example: Data Cleansing Functions .pull-left[ Numeric Cleansing ```r remove_outliers <- function(value) { case_when( value < 0 ~ NA_real_, value > 10 ~ NA_real_, TRUE ~ value ) } remove_outliers(c(1, -2, 3, 11)) ``` ``` [1] 1 NA 3 NA ``` ] .pull-right[ Character Cleansing ```r remove_undefined <- function(value) { ifelse( value %in% c('undergraduate', 'graduate'), value, NA) } remove_undefined( c("undergraduate", "freshman", "graduate", "supersenior") ) ``` ``` [1] "undergraduate" NA "graduate" [4] NA ``` ] ??? - These sample functions remove out-of-range values (numeric or string). --- # Example: FizzBuzz This code solves the classic [FizzBuzz problem](https://en.wikipedia.org/wiki/Fizz_buzz). ```r play_fizzbuzz <- function(fbnums) { case_when( fbnums %% 15 == 0 ~ "FizzBuzz", fbnums %% 3 == 0 ~ "Fizz", fbnums %% 5 == 0 ~ "Buzz", TRUE ~ as.character(fbnums) ) } play_fizzbuzz(1:25) ``` ``` [1] "1" "2" "Fizz" "4" "Buzz" [6] "Fizz" "7" "8" "Fizz" "Buzz" [11] "11" "Fizz" "13" "14" "FizzBuzz" [16] "16" "17" "Fizz" "19" "Buzz" [21] "Fizz" "22" "23" "Fizz" "Buzz" ``` .footnote[See: https://en.wikipedia.org/wiki/Fizz_buzz] ??? - This demos all the control structures: - explicit sequence and selection - implicit repetition - function abstraction References: - https://towardsdatascience.com/how-to-solve-the-fizzbuzz-problem-in-r-c62e7e6c959a