Source file ⇒ Lab_6.Rmd
If-else statements are perhaps the simplest type of control flow structure:
x <- 1 # Change this value to check if your code works
if (x > 0) {
print("positive")
} else {
print("not positive")
}
## [1] "positive"
Of course, the else is not necessary (if you don’t want anything to occur otherwise), or you can chain multiple if-else statements:
y <- 4 # Change this value to check if your code works
if (y > 0) {
print("positive")
} else if (y < 0) {
print("negative")
} else {
print("zero")
}
## [1] "positive"
Your turn! Write R code that will “squish” a number into the interval [0, 100], so that a number less than 0 is replaced by 0 and a number greater than 100 is replaced by 100.
z <- 100*pi
# Fill in the following if-else statements. You may (or may not) have to add or subtract else if or else statements.
if (z < 0) {
print("0")
} else if (z > 100) {
print("100")
} else {
print(z)
}
z <- 100*pi
# Fill in the following if-else statements. You may (or may not) have to add or subtract else if or else statements.
if (z < 0) { # Replace TRUE with a condition.
print("0")
} else if (z > 100) {
print("100")
} else {
print(z)
}
## [1] "100"
Loops are used when you want to perform a given task many times.
The simplest type of loop in R is the repeat loop, which will repeatedly evaluate a set of expressions until it is told to stop.
# Divide a number by 2 until it becomes odd.
val_rep <- 64
repeat {
print(val_rep)
if (val_rep %% 2 == 1) { # If val_rep is odd,
break # end the loop.
}
val_rep <- val_rep / 2 # Divide val_rep by 2 since val_rep was even.
# When the end of the loop is reached, return to the beginning of the loop.
}
## [1] 64
## [1] 32
## [1] 16
## [1] 8
## [1] 4
## [1] 2
## [1] 1
Often you will want to perform a loop until some condition is satisfied, or as long as a condition as satisfied. In that case, a while loop may be more appropriate.
val_while <- 243
while (val_while %% 2 == 0) { # Continue the loop as long as val_while is even.
print(val_while)
val_while <- val_while / 2
}
print(val_while)
## [1] 243
Notice that the while loop code is more compact (ignoring the print statements), since the stopping condition has been encoded in the loop itself.
Your turn! Write R code which multiplies a positive number by 3 and adds 1 until the result is greater than 10000. For example, 2015 \(\to\) 6046 \(\to\) 18139. Write both a repeat loop and a while loop.
n_rep <- 314 # Play with this value! Does your code behave as expected?
repeat { print(n_rep)
if(n_rep >10000) {
break
}
n_rep <- (abs(n_rep)*3) + 1
}
n_rep <- 314 # Play with this value! Does your code behave as expected?
repeat { print(n_rep)
if(n_rep >10000) {
break # Replace this with your code.
}
n_rep <- (abs(n_rep)*3) + 1
}
## [1] 314
## [1] 943
## [1] 2830
## [1] 8491
## [1] 25474
n_while <- 314
while (n_while < 10000) {
print(n_while)
n_while <- abs(n_while)*3 +1
}
n_while <- 314
while (n_while < 10000) {
print(n_while)
n_while <- abs(n_while)*3 +1
}
## [1] 314
## [1] 943
## [1] 2830
## [1] 8491
Sometimes instead of performing an action until a condition is satisfied, you just want to perform it a specified number of times. In these cases, a for loop is appropriate.
for (i in 1:10) { # Repeat 10 times.
print("Hello world!")
}
## [1] "Hello world!"
## [1] "Hello world!"
## [1] "Hello world!"
## [1] "Hello world!"
## [1] "Hello world!"
## [1] "Hello world!"
## [1] "Hello world!"
## [1] "Hello world!"
## [1] "Hello world!"
## [1] "Hello world!"
for (i in 1:10) { # Repeat 10 times.
print(i+1)
}
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9
## [1] 10
## [1] 11
Your turn again! Write a for loop to add 1 to every element of a vector in place. In other words, at the end of the operation vec should change from (3, 1, 4) to (4, 2, 5).
vec <- c(3, 1, 4)
for (i in 1:length(vec)) {
vec[i] <-(vec[i] + 1)
print(vec)
}
## [1] 4 1 4
## [1] 4 2 4
## [1] 4 2 5
Often you will find that it is easier to begin writing code for a specific task, with specific variables, before generalizing the code into a function. In the example above, we saw the following code, which divides a positive integer by 2 until it becomes odd.
x <- 898128000 # Example value
while (x %% 2 == 0) {
print(x)
x <- x / 2
}
## [1] 898128000
## [1] 449064000
## [1] 224532000
## [1] 112266000
## [1] 56133000
## [1] 28066500
## [1] 14033250
print(x)
## [1] 7016625
Your turn!
Now generalize the above code to create a function which performs the same operation without printing the intermediate steps. (You should change very little.)
reduce <- function(x) {
while (x %% 2 == 0) {
x <- x / 2
}
return(x)
}
reduce(898128000)
## [1] 7016625
How about something a little bit more complicated? Write a function f which, given a positive integer n, returns n / 2 if n was even or 3 * n + 1 if n was odd.
f <- function(n) {
if (n %% 2 == 0){
n <- n/2
} else if (n %% 2 != 0){
n <- (3 * n + 1)
}
return(n)
}
f(6) # Should return 3
## [1] 3
f(19) # Should return 58
## [1] 58
f(27) # Should return 82
## [1] 82
Now create function g which applies f() to a positive integer n until it becomes 1, and returns the number of iterations until this occurs.
i <-0
g <- function(n) {
while(n!=1) {
i <- i+1
n <-f(n)
}
return(i)
}
g(6) # Should return 8
## [1] 8
g(19) # Should return 20
## [1] 20
g(27) # Should return 111
## [1] 111
If you didn’t earlier, try also writing the same function, but now create f() as a nested function. If you did, write the same function but without f() as a nested function.
h <- function(n) {
f <- function(n) {
if (n %% 2 == 0){
n <- n/2
} else if (n %% 2 != 0) {
n <- (3 * n + 1)
}
}
i<-0
{
while(n!=1) {
i <- i+1
n <-f(n)
}
}
return(i)
}
h(6) # Should return 8
## [1] 8
h(19) # Should return 20
## [1] 20
h(27) # Should return 111
## [1] 111
As you probably know by now, many functions come with default arguments, which can be left unspecified without affecting the execution of the function.
The following function attempts to compute the length of the hypotenuse of a right triangle, but will accept one or two leg lengths.
pythagoras <- function(a, b = a) {
return(sqrt(a^2 + b^2))
}
pythagoras(3, 4)
## [1] 5
pythagoras(5)
## [1] 7.071068
Write a function which adds together the elements of a vector raised to a certain power. Use a loop instead of vectorized operations. Include two arguments: vec and pow. Give pow a default value of 2.
# Remove eval = FALSE or set eval = TRUE when you have completed this function.
powersum <- function(vec, pow = 2) {
sum = 0
for (i in 1:length(vec)){
sum <- sum + vec[i]^pow
}
}
powersum(1:5) # Should return 55.
powersum(1:5, 4) # Should return 979.
If you have time you can get started on your first homework problem:
Write a function that takes a number year and returns a logical value which is either TRUE, if the year was or will be a leap year, or FALSE if not. The rule for determining leap years is that one of the following conditions must hold:
the year is divisible by 4 but not divisible by 100, or
the year is divisible by 400.
Now write an R expression using your function to calculate how many leap years you have lived through during your lifetime.
leapyr <- function(year) {
if(year %% 4 == 0) {
if (year %% 100 == 0){
return(FALSE)
}else{
return(TRUE)
}
}
else{
return(FALSE)
}
}
leapyr(2000)
## [1] FALSE