?Control
?ifelse5 Control flow
5.1 Quiz
5.1.1 Quiz 1
What is the difference between if and ifelse()?
Answers
The difference between these conditions are: - if() operates on a single logical value - ifelse() operates on a vector of logical values. Syntax is also different.
# if
x <- TRUE
if (x) {
print("Hello")
}[1] "Hello"
# ifelse
x <- c(TRUE, FALSE, TRUE, TRUE)
ifelse(
x,
print("Hello"),
print("Goodbye")
)[1] "Hello"
[1] "Goodbye"
[1] "Hello" "Goodbye" "Hello" "Hello"
5.1.2 Quiz 2
In the following code, what will the value of y be if x is TRUE? What if x is FALSE? What if x is NA?
y <- if (x) 3Answers
Outcome of all cases are: - x <- TRUE: y is assigned. - x <- FALSE: y is NULL - x <- NA: Error.
# Let's test
## x is TRUE
x <- TRUE
y <- if (x) 3
y[1] 3
## x is FALSE
x <- FALSE
y <- if (x) 3
yNULL
## x is NA
x <- NA
y <- if (x) 3Error in `if (x) ...`:
! missing value where TRUE/FALSE needed
yNULL
5.1.3 Quiz 3
What does switch("x", x = , y = 2, z = 3) return?
Answers
switch evaluates the matched element or the first following non-missing argument. Since x is missing, the next argument y is evaluated, yielding 2.
switch("x",
x = ,
y = 2,
z = 3
)[1] 2
5.2 Choices
5.2.1 Ex. 1
What type of vector does each of the following calls to ifelse() return?
ifelse(TRUE, 1, "no")
ifelse(FALSE, 1, "no")
ifelse(NA, 1, "no")Answers
# Evaluates to the TRUE arg, 1
ifelse(TRUE, 1, "no")[1] 1
# Evaluates to the FALSE arg, no
ifelse(FALSE, 1, "no")[1] "no"
# NA propagates, result is NA
ifelse(NA, 1, "no")[1] NA
5.2.2 Ex. 2
Why does the following code work?
x <- 1:10
if (length(x)) {
"not empty"
} else {
"empty"
}[1] "not empty"
x <- numeric()
if (length(x)) {
"not empty"
} else {
"empty"
}[1] "empty"
Answers
The code works because:
- For the vector
1:10, its length is 10 and is equal toTRUE. - For the vector
numeric(), its length is 10 and is equal toFALSE.
# Length of x is 10, equal to TRUE
x <- 1:10
length(x)[1] 10
length(x) == TRUE[1] FALSE
# Length of x is 0, equal to FALSE
x <- numeric()
length(x)[1] 0
length(x) == FALSE[1] TRUE
5.3 Loops
5.3.1 Ex. 1
Why does this code succeed without errors or warnings?
x <- numeric()
out <- vector("list", length(x))
for (i in 1:length(x)) {
out[i] <- x[i]^2
}
out[[1]]
[1] NA
Answers
This horrorshow works because:
vector()by default, creates an empty vector. This behaviour is intended.1:length(x)is a vector counting down from 1 to 0 (c(1, 0))
# Example case
x1 <- vector(
mode = "list",
length = numeric() %>%
length()
)
# Default case
x2 <- vector(
mode = "list"
)
identical(x1, x2)[1] TRUE
During the first iteration, the following occurs:
- The subsetting of
xsuccessfully returnsNAas intended. - The
out[1]list element is successfully set as intended.
x <- numeric()
out <- vector("list", length(x))
out[1] <- x[1]^2During the second iteration, the following occurs:
- The subsetting of
xreturns a zero length vector not containing any data. - The subsetting of
outreturns a zero length vector not containing any data. - No data accessed or modified.
x <- numeric()
out <- vector("list", length(x))
out[0] <- x[0]^2In summary, all operations behaved as intended by the code and contained no errors.
5.3.2 Ex. 2
When the following code is evaluated, what can you say about the vector being iterated?
xs <- c(1, 2, 3)
for (x in xs) {
xs <- c(xs, x * 2)
}
xs[1] 1 2 3 2 4 6
Answers
In every iteration, the calculated value is concatenated with the previous vector and attached to the end. The for looping section is evaluated prior to beginning the loop, which ensures that the loop ends in 3 iterations, even though the length of xs is increased by the loop.
xs <- c(1, 2, 3)
for (x in xs) {
xs <- c(xs, x * 2)
print(xs)
}[1] 1 2 3 2
[1] 1 2 3 2 4
[1] 1 2 3 2 4 6
5.3.3 Ex. 3
for (i in 1:3) {
i <- i * 2
print(i)
}[1] 2
[1] 4
[1] 6
Answers
In essence, there are two different i variables here:
- The first
iis outside of the loop and is responsible for counting the number of iterations (1, 2, 3) - The second
iis inside the loop.
At every iteration, the outer i is passed in the loop, doubled, printed, then replaced with the outer i when the next iteration begins. The outer i is never modified.