library("tidyverse")
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.2 ──
## ✔ ggplot2 3.4.0 ✔ purrr 0.3.5
## ✔ tibble 3.1.8 ✔ dplyr 1.0.10
## ✔ tidyr 1.2.1 ✔ stringr 1.4.1
## ✔ readr 2.1.3 ✔ forcats 0.5.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
Control structures in R provide conditional flow as well as looping.
An R expression
is evaluated within the loop or as the
result of a conditional statement.
The following are example R expressions
# First expression
1+2
## [1] 3
# Second expression
a <- 1; b <- 2; a+b
## [1] 3
# Third expression
{
a <- 1
b <- 2
a + b
}
## [1] 3
See
?expression
Conditionals include if-else type statements
if (TRUE) {
print("This was true!")
}
## [1] "This was true!"
this <- TRUE
if (this) {
print("`this` was true!")
}
## [1] "`this` was true!"
if (1<2) {
print("one is less than two!")
}
## [1] "one is less than two!"
if (1>2) {
print("one is greater than two!")
}
Using variables
a <- 1
b <- 2
if (a < 2) {
print("`a` is less than 2!")
}
## [1] "`a` is less than 2!"
if (a < b) {
print("`a` is less than `b`!")
}
## [1] "`a` is less than `b`!"
if (a < b) {
print("`a` is less than `b`!")
} else {
print("`b` is not less than `a`!")
}
## [1] "`a` is less than `b`!"
if (a > b) {
print("`a` is greater than `b`!")
} else {
print("`a` is not greater than `b`!")
}
## [1] "`a` is not greater than `b`!"
if (a > b) {
print("`a` is greater than `b`!")
} else if (dplyr::near(a,b)) {
print("`a` is near `b`!")
} else {
print("`a` must be greater than b")
}
## [1] "`a` must be greater than b"
You can omit the brackets { } for single line expressions
if (a < b)
print("`a` is less than `b`!")
## [1] "`a` is less than `b`!"
The ifelse()
function takes a logical vector as a first
argument and then two scalars.
ifelse(c(TRUE, FALSE, TRUE), "this was true", "this was false")
## [1] "this was true" "this was false" "this was true"
A rarely used function is switch()
which implements a
case-switch comparison.
this <- "a"
switch(this,
a = "`this` is `a`",
b = "`this` is `b`",
"`this` is not `a` or `b`")
## [1] "`this` is `a`"
this <- "b"
switch(this,
a = "`this` is `a`",
b = "`this` is `b`",
"`this` is not `a` or `b`")
## [1] "`this` is `b`"
this <- "c"
switch(this,
a = "`this` is `a`",
b = "`this` is `b`",
"`this` is not `a` or `b`")
## [1] "`this` is not `a` or `b`"
There are 3 base types of loops: for
,
while
, and repeat
.
These loops use the reserved words for
and
in
,
The most common use of a for
loop is to loop over
integers.
for (i in 1:10) {
print(i)
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9
## [1] 10
for (i in 1:10) {
if (i > 5)
print(i)
}
## [1] 6
## [1] 7
## [1] 8
## [1] 9
## [1] 10
Can also iterate over non-integers
for (d in c(2.3, 3.5, 4.6)) {
print(d)
}
## [1] 2.3
## [1] 3.5
## [1] 4.6
for (c in c("my","char","vector")) {
print(c)
}
## [1] "my"
## [1] "char"
## [1] "vector"
While these are possible, I find I rarely use them.
seq_along()
Be careful when iterating over objects that a potentially NULL.
this <- NULL
for (i in 1:length(this)) {
print(i)
}
## [1] 1
## [1] 0
Since this
had no length, you probably didn’t want to
enter the for
loop at all. To be safe, you can use
seq_along()
.
for (i in seq_along(this)) {
print(i)
}
my_chars <- c("my","char","vector")
for (i in seq_along(my_chars)) {
print(paste(i, ":", my_chars[i]))
}
## [1] "1 : my"
## [1] "2 : char"
## [1] "3 : vector"
seq_len()
For data.frame
s use seq_len()
with
nrow()
.
for (i in seq_len(nrow(ToothGrowth))) {
if (ToothGrowth$supp[i] == "OJ" &
near(ToothGrowth$dose[i], 2) &
ToothGrowth$len[i] > 25) {
print(ToothGrowth[i,])
}
}
## len supp dose
## 51 25.5 OJ 2
## len supp dose
## 52 26.4 OJ 2
## len supp dose
## 56 30.9 OJ 2
## len supp dose
## 57 26.4 OJ 2
## len supp dose
## 58 27.3 OJ 2
## len supp dose
## 59 29.4 OJ 2
Like with if
and else
statements,
for
loops can omit the brackets { } for single line
expressions.
for (i in 1:10)
print(i)
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9
## [1] 10
The while()
loop can be used to construct while
loops.
a <- TRUE
while (a) {
print(a)
a <- FALSE
}
## [1] TRUE
i <- 0
while (i < 10) {
print(i)
i <- i + 1
}
## [1] 0
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9
x <- 2
while (x < 1) { # Evaluated before the loop
print("We entered the loop.")
}
while (x < 100) { # Evaluated after each loop
x <- x*x
print(x)
}
## [1] 4
## [1] 16
## [1] 256
Be careful about infinite loops
while (TRUE) {
# do something
}
You can typically Escape out of infinite loops. Often, you will want to make sure the infinite loop never occurs.
max_iterations <- 1000
i <- 1
while (TRUE & (i < max_iterations) ) {
i <- i + 1
# Do something
}
print(i)
## [1] 1000
An alternative to while()
is repeat
combined with break
.
i <- 10
repeat {
print(i)
i <- i + 1
if (i > 13)
break
}
## [1] 10
## [1] 11
## [1] 12
## [1] 13
i <- 1
repeat {
print(i)
i <- i + 1
if (i %% 2) { # %% is the mod function, 0 is FALSE and 1 is TRUE
next # skips to next iteration of repeat
}
if (i > 14)
break
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9
## [1] 10
## [1] 11
## [1] 12
## [1] 13
## [1] 14
## [1] 15