Control Flow






Grayson White

Math 241
Week 9 | Spring 2026

Annoucements

  • Project 1 Timeline Updates
    • Final product and Data Scientist Statement due Sunday April 5th at 10pm instead of Friday April 3rd at 10pm.
    • Group member feedback form is now due Tuesday April 7th at 10pm instead of Sunday April 5th at 10pm.

Post Spring Break: Big Picture Goals

  • Three days: Core R programming skills: control flow, functions, iteration (loops and functional programming)
    • Problem set 5 on this material
  • Two days on ethics and AI
    • Problem set 6 on this material
  • Three days on writing your own R packages
    • Project 2 will be centrally focused on writing your own R package
    • We’ll have a project work day during the last week of class
  • Last day of class: Building your data science profile: Github and personal professional website

Post Spring Break: Assignments / deadlines

  • Project 1
    • Final product and Data Scientist Statement due Sunday April 5th at 10pm
    • Group member feedback form due Tuesday April 7th at 10pm
  • Problem Set 5
    • Released Tuesday April 7th at 9am, due Wednesday April 15th at 10pm
  • Problem Set 6
    • Released Tuesday April 14th at 9am, due Wednesday April 21st at 10pm
  • Project 2
    • Released Tuesday April 21st, Due Wednesday May 13th at noon

Today: Control Flow

Control Flow

  • The flow of execution of R code.

  • So far, our primary rule: Place your code in the order that you want R to evaluate it.

Incorrect order:

crash_data <- read_csv("data/pdx_crash_2018_page1.csv") 
Error in `read_csv()`:
! could not find function "read_csv"
library(tidyverse)


Correct order:

library(tidyverse)
crash_data <- read_csv("data/pdx_crash_2018_page1.csv") 

Control Flow

  • Can also get R to conditionally run code blocks or run code blocks multiple times.

  • Control structures allow you to control the flow of execution.

  • Main tools we will use to control the flow:

    • if() and else()
    • stop() and stopifnot()
    • for() loops
die_roll <- sample(1:6, size = 1)
if(die_roll == 6) {
    print("Biggest number!")
  } else {
    print(die_roll)
  }
[1] 1
for(i in 1:6){
  print(i * 10)
}
[1] 10
[1] 20
[1] 30
[1] 40
[1] 50
[1] 60

Come Back to Logical Operators

  • To control the flow, we need to be really comfortable with logical operators.

Or operators:

a <- c(TRUE, FALSE, FALSE, TRUE)
b <- c(TRUE, FALSE)

a | b
[1]  TRUE FALSE  TRUE  TRUE
a || b
Error in `a || b`:
! 'length = 4' in coercion to 'logical(1)'
xor(a, b)
[1] FALSE FALSE  TRUE  TRUE
  • Which is vectorized?
  • What is recycling again?
  • What is going on with ||?

Logical Operators

And operators:

a <- c(TRUE, FALSE, FALSE, TRUE)
b <- c(TRUE, FALSE)

a & b
[1]  TRUE FALSE FALSE FALSE
a && b
Error in `a && b`:
! 'length = 4' in coercion to 'logical(1)'
  • Which is vectorized?
  • What is recycling again?
  • What is going on with &&?

Element-wise comparison (& and |) vs. single-element comparison (&& and ||)

Element-wise comparison:

a <- c(TRUE, FALSE, FALSE, TRUE)
b <- c(TRUE, FALSE)
a & b
[1]  TRUE FALSE FALSE FALSE
a | b
[1]  TRUE FALSE  TRUE  TRUE

Single-element comparison:

a && b
Error in `a && b`:
! 'length = 4' in coercion to 'logical(1)'
a || b
Error in `a || b`:
! 'length = 4' in coercion to 'logical(1)'


a <- TRUE
b <- FALSE
a && b
[1] FALSE
a || b
[1] TRUE
  • More exploration of && and || in our activity today
  • For further discussion of the differences, see here

Logical Operators

Not operator:

a <- c(TRUE, FALSE, FALSE, TRUE)
b <- c(TRUE, FALSE)

!a
[1] FALSE  TRUE  TRUE FALSE
!a & b
[1] FALSE FALSE  TRUE FALSE
!(a & b)
[1] FALSE  TRUE  TRUE  TRUE

Comparison Operators

x <- c(1, 3, 5)
y <- c(1, 4, 2)
z <- c(3, 2)


x < y
x <= y
x > y
x >= y
x == y
x != y
x != z
z %in% x
x %in% z

Comparison Operators

x <- c(1, 3, 5)
y <- c(1, 4, 2)
z <- c(3, 2)


x < y
[1] FALSE  TRUE FALSE
x <= y
[1]  TRUE  TRUE FALSE
x > y
[1] FALSE FALSE  TRUE
x >= y
[1]  TRUE FALSE  TRUE
x == y
[1]  TRUE FALSE FALSE
x != y
[1] FALSE  TRUE  TRUE
x != z
[1] TRUE TRUE TRUE
z %in% x
[1]  TRUE FALSE
x %in% z
[1] FALSE  TRUE FALSE
  • Operators are just functions with funky notation
  • Typically, we use operators with infix notation:
x == y
[1]  TRUE FALSE FALSE
  • However, we can use prefix notation just like other functions we are used to:
`==`(x, y)
[1]  TRUE FALSE FALSE
  • Note the use of backticks.

  • This works for all operators!

Conditional Control Flow

R will conditionally execute code via if statements.

The basic one-line form is:

if (condition) true_action
if (condition) true_action else false_action

The basic multi-line form is:

if (condition) {
  true_action
}

if (condition) {
  true_action
} else {
  false_action
}

Conditional Control Flow

R will conditionally execute code via if statements.

x <- c(1, 3, 5)

if (3 %in% x){
  print("Vector contains 3.")
}
[1] "Vector contains 3."
if (4 %in% x){
  print("Vector contains 4.")
}


if (4 %in% x){
  print("Vector contains 4.")
} else {
  print("Vector does not contain 4.")
}
[1] "Vector does not contain 4."

Conditional Control Flow

if() is not vectorized!

x <- c(1, 3, 5)

if (x == 1){
  print("Vector contains 1.")
}
Error in `if (x == 1) ...`:
! the condition has length > 1
if (x == 3){
  print("Vector contains 3.")
}
Error in `if (x == 3) ...`:
! the condition has length > 1
  • Alternative condition?

Conditional Control Flow

if() is not vectorized! Alternative condition?

if (x %in% 3){
  print("Vector contains 3.")
}

Conditional Control Flow

if() is not vectorized! Alternative condition?

if (x %in% 3){
  print("Vector contains 3.")
}
Error in `if (x %in% 3) ...`:
! the condition has length > 1

Conditional Control Flow

if() is not vectorized! Alternative condition?

if (x %in% 3){
  print("Vector contains 3.")
}
Error in `if (x %in% 3) ...`:
! the condition has length > 1


if (3 %in% x){
  print("Vector contains 3.")
}
[1] "Vector contains 3."

Collapsing Logical Vectors

Because if is not vectorized, it is often helpful to collapse logical vectors to a single value.

  • Enter: any() and all()


x <- c(1, 3, 5)
any(x == 1)
[1] TRUE
if (any(x == 1)){
  print("Vector contains 1.")
}
[1] "Vector contains 1."
if (any(x == 3)){
  print("Vector contains 3.")
}
[1] "Vector contains 3."
all(x <= 4)
[1] FALSE
all(x <= 5)
[1] TRUE

Continuing the Conditional Executions

x = 3

if (x < 0) {
  print("x is negative")
} else if (x > 0) {
  print("x is positive")
} else {
  print("x is zero")
}
[1] "x is positive"
x = 0

if (x < 0) {
  print("x is negative")
} else if (x > 0) {
  print("x is positive")
} else {
  print("x is zero")
}
[1] "x is zero"

Saving Results

height_in <- 82
if (height_in >= 84) {
    "Center"
  } else if (height_in >= 78) {
    "Forward"
  } else if (height_in >= 75) {
    "Shooting Guard"
  } else {
    "Point Guard"
  }
[1] "Forward"
if (height_in >= 84) {
    position <- "Center"
  } else if (height_in >= 78) {
    position <- "Forward"
  } else if (height_in >= 75) {
    position <- "Shooting Guard"
  } else {
    position <- "Point Guard"
  }
position
[1] "Forward"

Vectorized if() else()

  • ifelse() runs operations on an entire vector.
height_in <- c(82, 74, 87)
position <- ifelse(height_in >= 84,
                   "Center",
                   "not Center")
position
[1] "not Center" "not Center" "Center"    
  • case_when() provides a more flexible alternative.
position <- case_when(
  height_in >= 84 ~ "Center",
  height_in >= 78 ~ "Forward",
  height_in >= 75 ~ "Shooting Guard",
  TRUE ~ "Point Guard"
)
position
[1] "Forward"     "Point Guard" "Center"     

Error Checking

  • Often want to validate user inputs or function assumptions.
    • Will see this in action next time when discussing functions.
  • If an input is incorrect or an assumption isn’t met, then want to report the error and stop the code.
height_in <- c(82, 74, 87)
stopifnot(is.character(height_in))
Error:
! is.character(height_in) is not TRUE
stopifnot(is.numeric(height_in))
  • Want a more helpful error message!

Error Checking

Alternative for more informative error messages:

  • Check inputs with if()
  • And then stop() if they are wrong.
height_in <- c(82, 74, 87)
 if(!is.character(height_in)) {
    stop('This function only works for character inputs.\n',
         'You have provided an object of class: ', class(x))
 }
Error:
! This function only works for character inputs.
You have provided an object of class: numeric

Control Flow Recap

  • The flow of execution of R code.

  • Order still matters.

  • But now we can:

    • Run subsets of the code with if() and else().
    • Check for errors with stop().
  • Very helpful for building functions (Wednesday)

  • Will add in for() loops and other iteration methods next week.

  • Also need to weave in best practices.

    • Lots of ways to do something. Which is best?

Activity Time