While Loop and More about Functions

Reading Assignments

While Loop

  • Use for loop – when you know how many times a given computation needs to be repeated.
  • Use while loop – repeat a process without necessarily knowing how many times this repetition will take place

The generic syntax of while loop is:

iterator <- initial

while (condition) {
  do_something
  iterator <- iterator + 1
}

Example:

i <- 1
while (i <= 3) {
    cat(sprintf("%d, ", i))
    i <- i + 1
}
#> 1, 2, 3,

# For comparison
i <- 1
while (i <= 3) {
    print(i)
    i <- i + 1
}
#> [1] 1
#> [1] 2
#> [1] 3

cat vs print

print("I will not buy this record.\n It is scratched.\n")
#> [1] "I will not buy this record.\n It is scratched.\n"
cat("I will not buy this record.\n It is scratched.\n")
#> I will not buy this record.
#>  It is scratched.

sprintf

x = letters[3:1]

for(i in 1:3){
  cat(sprintf("Obs %d is %s.", i, x[i]), "\n")
}
#> Obs 1 is c. 
#> Obs 2 is b. 
#> Obs 3 is a.

Please find more information about sprintf in Section 6.1.4 at https://deepr.gagolewski.com/chapter/160-character.html or help(sprintf)

Example 14.3

set.seed(234)  # for replication purposes

# vector of 10 random integers between 1 and 100
random_numbers = sample.int(n = 100, size = 10, replace = FALSE)
random_numbers = sort(random_numbers)
random_numbers
#>  [1]  1 18 31 34 46 56 68 92 97 98
# initialize object of cumulative sum
total_sum = 0

# declare iterator
pos = 0

# repetitive steps
while (total_sum <= 100) {
  pos = pos + 1
  total_sum = total_sum + random_numbers[pos]
}

# what is the value of the cumulative sum?
total_sum
#> [1] 130
# how many iterations were necessary?
pos
#> [1] 5

The next and break statements

  • next – skipping certain iterations
  • break – stop a loop from iterating

Loop using repeat

Example of using repeat and break:

x = 42

repeat {
  print(x)
  if (x < 1) {
    break
  }
  x = sqrt(x) - 1
}
#> [1] 42
#> [1] 5.480741
#> [1] 1.341098
#> [1] 0.1580579


# Equivalently,

x = 42

while (x >=1){
  if(x==42) print(x)
  x = sqrt(x) - 1
  print(x)
}
#> [1] 42
#> [1] 5.480741
#> [1] 1.341098
#> [1] 0.1580579

More About Functions: Nested Functions

Example 15.1.2

getmax = function(a) {
  # nested function
  maxpos <- function(u){
    which.max(u)  
  }
  
  # output
  list(position = maxpos(a),
       value = max(a))
}
getmax(c(2, -4, 6, 10, pi))
#> $position
#> [1] 4
#> 
#> $value
#> [1] 10

More About Functions: Lexical Scoping

R’s lexical scoping follows four primary rules:

  • Name masking
  • Functions versus variables
  • A fresh start
  • Dynamic lookup

Name Masking

  • Name defined inside a function mask names defined outside a function.
x <- 10
y <- 20

g02 <- function() {
  x <- 1
  y <- 2
  c(x, y)
}

g02()
#> [1] 1 2
x <- 2
g03 <- function() {
  y <- 1
  c(x, y)
}
g03()
#> [1] 2 1

x
#> [1] 2
y
#> [1] 20

Functions versus variables

  • Function_names defined inside a function mask function_names defined outside a function.
g07 <- function(x) x + 1
g08 <- function() {
  g07 <- function(x) x + 100
  g07(10)
}
g08()
#> [1] 110
  • When a function and a non-function share the same name, R ignores non-function objects when looking for that value.
g09 <- function(x) x + 100
g10 <- function() {
  g09 <- 10
  g09(g09)
}
g10()
#> [1] 110

A fresh start

g11 <- function() {
  if (!exists("a")) {
    a <- 1
  } else {
    a <- a + 1
  }
  a
}

g11()
#> [1] 1
g11()
#> [1] 1

Dynamic lookup

g12 <- function() x + 1
x <- 15
g12()
#> [1] 16
#> [1] 16

x <- 20
g12()
#> [1] 21
#> [1] 21

More About Functions: Signalling Conditions

is_even_or_odd <- function(x){
  if (!is.integer(x)){
    stop("Not a whole number")
    } else if (x %% 2 == 0){
      return("even")
      } else {
        return("odd")
      }
}


is_even_or_odd(5.5)
#> Error in is_even_or_odd(5.5): Not a whole number
  • stop() can also be used in for loops.

Example:

for(i in 1:10){
  if(i %% 5 == 0){
    stop("A multiple of 5") # break & error message
  }
  print(i)
}
#> [1] 1
#> [1] 2
#> [1] 3
#> [1] 4
#> Error in eval(expr, envir, enclos): A multiple of 5
# For comparison purpose

for(i in 1:10){
  if(i %% 5 == 0){
    break
  }
  print(i)
}
#> [1] 1
#> [1] 2
#> [1] 3
#> [1] 4

More on signalling conditions

  • There are three conditions that you can signal in code: errors, warnings, and messages.

    • Errors are the most severe. Severe issue \(\Rightarrow\) the execution of the program should stop immediately.
    • Warnings fall somewhat in between errors and message. Condition is not critical, the program will continue to run, but the user should be alerted about potential issues.
    • Messages are the mildest. For informational purposes, the flow of the program is not interfered.
  • Please find more information at https://adv-r.hadley.nz/conditions.html?q=while#signalling-conditions

  • Warning

for(i in 1:10){
  if(i %% 5 == 0){
    warning("A multiple of 5")
  }
  print(i)
}
#> [1] 1
#> [1] 2
#> [1] 3
#> [1] 4
#> Warning: A multiple of 5
#> [1] 5
#> [1] 6
#> [1] 7
#> [1] 8
#> [1] 9
#> Warning: A multiple of 5
#> [1] 10
  • Message
for(i in 1:10){
  if(i %% 5 == 0){
    message("A multiple of 5")
  }
  print(i)
}
#> [1] 1
#> [1] 2
#> [1] 3
#> [1] 4
#> A multiple of 5
#> [1] 5
#> [1] 6
#> [1] 7
#> [1] 8
#> [1] 9
#> A multiple of 5
#> [1] 10

More About Functions: For Readable Codes

White Spaces

Example:

if (!is.vector(x)) {
  stop('x must be a vector')
} else {
  if (any(is.na(x))) {
    x <- x[!is.na(x)]
  }
  total <- length(x)
  x_sum <- 0
  for (i in seq_along(x)) {
    x_sum <- x_sum + x[i]
  }
  x_sum / total
}

Left parenthesis should start immediately after a function name

# NOT Recommended 
read.table ('data.csv', header = TRUE, row.names = 1)

# Recommended 
read.table('data.csv', header = TRUE, row.names = 1)

Indention

Example:

# better with indentation
if (!is.vector(x)) {
  stop('x must be a vector')
} else {
  if (any(is.na(x))) {
    x <- x[!is.na(x)]
  }
  total <- length(x)
  x_sum <- 0
  for (i in seq_along(x)) {
    x_sum <- x_sum + x[i]
  }
  x_sum / total
}

Section 15.3.1 Meaningful Names https://www.gastonsanchez.com/R-coding-basics/5-06-more-functions.html#meaningful-names

Section 15.3.2 Syntax: Parentheses https://www.gastonsanchez.com/R-coding-basics/5-06-more-functions.html#syntax-parentheses