10  R: Control flow tools

10.1 Code Blocks: R vs. Python

Different programming languages define code blocks differently:

  • Python uses indentation to structure code.
  • R uses curly braces {} to define code blocks.

You have learned indentation (spaces or tabs) determines the structure of code in Python.

10.1.1 Code blocks in R (Uses {})

In R, curly braces {} define code blocks, and indentation is not required (but recommended for readability).

for (i in 1:5) {
  print(i)
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5

Another key difference in control flow syntax between Python and R is how conditions are written. In Python, conditions do not require parentheses, whereas in R, they must be enclosed in parentheses.

10.2 TryCatch

When running R code, errors can occur due to unexpected inputs, missing data, or issues with computations. Without proper error handling, an entire execution may be stopped due to an error. The tryCatch function in R provides a mechanism to handle errors gracefully, allowing execution to continue and custom responses to be provided.

Basic Syntax

tryCatch({
  # Code that may generate an error
}, error = function(e) {
  # Code to handle errors
}, warning = function(w) {
  # Code to handle warnings
}, finally = {
  # Code that will always execute
})
NULL
  • error: Handles errors that stop execution.
  • warning: Handles warnings that don’t necessarily stop execution.
  • finally: Executes code regardless of whether an error occurs.

Example: Input an integer from the user. If the user inputs a valid integer, print whether it is a multiple of 3. However, if the user does not input a valid integer, print a message saying that the input is invalid.

num <- "3r"
tryCatch({
  num_int <- as.integer(num)
  if (num_int %% 3 == 0) {
    print("Number is a multiple of 3")
  } else {
    print("Number is not a multiple of 3")
  }
}, error = function(e) {
  print("Error encountered")
}, warning = function(w) {
  print("Warning encountered")
})
[1] "Warning encountered"

The warning block will be triggered, not the error block.

Why

  • as.integer("3r") does not generate an error. Instead, it produces a warning and returns NA.
  • In R, an error occurs when an operation stops execution (e.g., division by zero in integer operations).
  • A warning occurs when something unexpected happens, but execution continues (e.g., invalid conversion).

10.3 Control flow tools

Control flow in R relies on comparison operators and logical operators to make decisions based on conditions. These operators are commonly used in conditional statements like if, ifelse(), and loops.

Like Python, R provides if-else, for loops, while loops, and switch/case for decision-making and iteration. However, in Python, conditions do not require parentheses, whereas in R, parentheses must enclose the condition.

x <- 5
while (x > 0) {  # Parentheses required
  print(x)
  x <- x - 1
}
[1] 5
[1] 4
[1] 3
[1] 2
[1] 1

10.4 Conditional statements

The if-else if-else statements can check several conditions, and execute the code corresponding to the condition that is true. Note that there can be as many else if statements as required.

Example: Assign letter grade based on a student’s final score

score <- 75  # Change this value to test different cases

if (score >= 90) {
  print("Grade: A")
} else if (score >= 80) {
  print("Grade: B")
} else if (score >= 70) {
  print("Grade: C")
} else if (score >= 60) {
  print("Grade: D")
} else {
  print("Grade: F")
}
[1] "Grade: C"

10.5 Loops

10.5.1 The : operator

The : operator in R is used to generate sequences of integers. It is similar to Python’s range() function, but with some key differences.

Basic Syntax

start:end

  • Generates a sequence of integers from start to end.
  • Inclusive: Both start and end are included.

Examples

1:5
[1] 1 2 3 4 5

In Python, the equivalent would be list(range(1, 6))

10.5.1.1 Reverse sequence

The : operator also works in Reverse

# Counting down
5:1
[1] 5 4 3 2 1

10.5.1.2 Using : with negative numbers

# Counting down
-3:3
[1] -3 -2 -1  0  1  2  3

10.5.1.3 Using : with Non-integers

If the start or end value is not an integer, R coerces it to an integer.

# The decimal values are truncated to integers before generating the sequence
1.5:5.5
[1] 1.5 2.5 3.5 4.5 5.5

10.5.2 seq() function

Difference: ``: only creates sequences with a step size of 1, while seq() allows custom increments.

# Counting by 2
seq(1, 10, by = 2)
[1] 1 3 5 7 9

Summary

Feature R (: Operator) Python (range()) R (seq() Function)
Generates integers ✅ Yes ✅ Yes ✅ Yes
Inclusive of end? ✅ Yes ❌ No (excludes end) ✅ Yes
Works in reverse? ✅ Yes (5:1) ✅ Yes (range(5, 0, -1)) ✅ Yes (seq(5, 1, by = -1))
Handles non-integers? ✅ Converts to integer ❌ Must be integer ✅ Supports non-integer steps
Custom step size? ❌ No (always 1) ✅ Yes (range(1, 10, 2)) ✅ Yes (seq(1, 10, by = 2))

10.5.3 for loop

The for loop is used when you need to iterate over a sequence of numbers, vectors, lists, or other iterable objects.

10.5.3.1 Using : in for loops

Since : creates integer sequences, it is commonly used in for loops.

for (i in 1:5) {
  print(i)
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5

Example: Print the first \(n\) elements of the Fibonacci sequence, where \(n\) is an integer input by the user, such that \(n>2\). In a fibonacci sequence, each number is the sum of the preceding two numbers, and the sequence starts from \(0,1\). The sequence is as follows:

\(0,1,1,2,3,5,8,13,....\)

n <- readline("Enter a number:")
Enter a number:
n <- 10
# Define the number of terms
if (n <= 0) {
  stop("n must be a positive integer")
}

# Initialize the sequence with the first two Fibonacci numbers
n1 <- 0
n2 <- 1
elements <- c(n1, n2)

# Generate the Fibonacci sequence iteratively
for (i in 3:n) {  
  n3 <- n1 + n2  # Compute the next term
  elements <- c(elements, n3)  # Append to the sequence
  
  # Shift values for the next iteration
  n1 <- n2
  n2 <- n3  
}

# Print the Fibonacci sequence
print(elements)
 [1]  0  1  1  2  3  5  8 13 21 34
cat("These are the first", n, "elements of the Fibonacci series.\n")
These are the first 10 elements of the Fibonacci series.
  • The stop() function in R is used to terminate execution and display an error message when a certain condition is met. It is often used for error handling to prevent further execution of the script when an invalid input is detected.
  • The c() function in R is used to combine values into a vector. It is one of the most fundamental functions in R, as vectors are the primary data structure. You can think of vectors as being similar to Python lists.

10.5.4 while loop

The whileloop executes as long as the specified condition evaluates to TRUE.

Example: Print all the elements of the Fibonacci sequence less than n, where n is an integer input by the user, such that n>2. In a fibonacci sequence, each number is the sum of the preceding two numbers, and the sequence starts from 0,1. The sequence is as follows:

0,1,1,2,3,5,8,13,..

n = readline("Enter a number:")
Enter a number:
n = 50
# Initialize the sequence with the first number
n1 <- 0
n2 <- 1

# Store the Fibonacci sequence
elements <- n1

# Generate Fibonacci numbers less than n
while (n2 < n) {
  elements <- c(elements, n2)  # Append the next number
  
  # Compute the next Fibonacci number
  n3 <- n1 + n2
  
  # Shift values for the next iteration
  n1 <- n2
  n2 <- n3  
}

# Print the Fibonacci sequence
print(elements)
 [1]  0  1  1  2  3  5  8 13 21 34
cat("These are all the Fibonacci numbers less than", n, "\n")
These are all the Fibonacci numbers less than 50 

10.6 Loop control statements

in R, there are two statements that are commonly used to control the execution of loops by altering their normal flow

10.6.1 break statement (Loop Termination)

The break statement is used to immediately exits the loop when certain condition is met. It will stop execution of the loop entirely

For example, suppose we need to keep asking the user to input year of birth and compute the corresponding age, until the user enters 1900 as the year of birth.

# Get current year dynamically
current_year <- as.integer(format(Sys.Date(), "%Y"))

# Check if running in interactive mode
if (interactive()) {
  while (TRUE) {
    user_input <- readline("Enter year of birth (1900-present) or 'q' to quit: ")
    
    if (tolower(user_input) == "q") {
      cat("Goodbye!\n")
      break
    }
    
    year <- suppressWarnings(as.integer(user_input))
    
    if (is.na(year)) {
      cat("Error: Please enter a valid year as a number.\n")
    } else if (year == 1900) {
      cat("Special year entered. Exiting program.\n")
      break
    } else if (year < 1900) {
      cat("Error: Year must be 1900 or later.\n")
    } else if (year > current_year) {
      cat("Error: Year cannot be in the future.\n")
    } else {
      age <- current_year - year
      cat(sprintf("Based on birth year %d, age in %d = %d years\n", 
                  year, current_year, age))
    }
  }
} else {
  cat("Skipping user input section since Quarto is running in batch mode.\n")
}

10.6.2 next statement (Skip Iteration, Similar to continue in Python)

The next statement is used to skip the current iteration and moves to the next one. It does not exit the loop but skips the rest of the current iteration.

For example, consider the following code:

for (i in 1:10) {
  if (i == 5) {
    next  # Skip iteration when i is 5
  }
  print(i)
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10

When the control flow reads the statement next, it goes back to the beginning of the for loop, and ignores the lines of code below the statement.

10.6.3 Practice exercise

Write a program that asks the user the question, “How many stars are in the Milky Way (in billions)?”. If the user answers 100, the program should print correct, and stop. However, if the user answers incorrectly, the program should print “incorrect”, and ask them if they want to try again. The program should continue to run until the user answers correctly, or they want to stop trying.

while (TRUE) {
  answer = readline("How many stars are there in the Milky Way (in billions)? ")
  if (answer == '100') {
    print("Correct")
    break
  } else {
    print("Incorrect")
  }
  try_again = readline("Do you want to try again? (Y/N):")
  if (try_again == 'Y') {
    next
  } else {
    break
  }
}

10.7 characters in R

10.7.1 Basic Definitions

  • In Python, strings are defined using either single (') or double (") quotes.
  • In R, character values (strings) are always enclosed in double quotes (" "), though single quotes (' ') also work, But single quotes are normally only used to delimit character constants containing double quotes.

10.7.2 String/Character Length

  • In Python, len() is used to count the number of characters.
  • In R, nchar() is used.
s <- "Hello"
print(nchar(s)) 
[1] 5

10.7.3 String Indexing and Slicing

  • Python allows direct indexing and slicing using [].
  • R does not support direct indexing for characters. Instead, substr() is used.
s <- "Hello"
print(substr(s, 2, 2))   # Output: "e" (1-based index)
[1] "e"
print(substr(s, 2, 4)) 
[1] "ell"

Key Difference: Python uses 0-based indexing, while R uses 1-based indexing.

10.7.4 String Concatenation

  • Python: Uses + for concatenation.
  • R: Uses paste() or paste0().
s1 <- "Hello"
s2 <- "World"
print(paste(s1, s2))   
[1] "Hello World"
print(paste0(s1, s2))
[1] "HelloWorld"

10.7.5 Changing Case (Uppercase & Lowercase)

  • Python: s.upper() and s.lower() for conversion
  • R: toupper(s) and tolower(s)
s <- "Hello"
print(toupper(s))
[1] "HELLO"
print(tolower(s))
[1] "hello"

10.7.6 Finding Substrings

  • Python: Uses .find() or in to check for substrings.
  • R: Uses grep() or grepl().
s <- "Hello World"
print(grepl("World", s))  
[1] TRUE
print(grep("World", s))
[1] 1

10.7.7 String Replacement

  • Python: Uses .replace().
  • R: Uses gsub().

10.7.8 String Splitting

  • Python: Uses split() method in strings to break them into lists
  • R: Uses strsplit() function to split strings into a list of character vectors.
sentence <- "Hello, how are you?"
words <- strsplit(sentence, " ")  # Split by space
print(words)
[[1]]
[1] "Hello," "how"    "are"    "you?"  

strsplit() returns a list, even if applied to a single string. The delimiter is treated as a regex, meaning special characters need to be escaped

# splitting using a comma
sentence <- "apple,banana,grape,orange"
words <- strsplit(sentence, ",")
print(words[[1]])
[1] "apple"  "banana" "grape"  "orange"

10.7.9 Summary table

Feature Python (String) R (Character)
Definition 'Hello' or "Hello" "Hello"
Data Type Check type("Hello")str class("Hello")"character"
Length len(s) nchar(s)
Indexing s[1] (0-based) substr(s, 2, 2) (1-based)
Concatenation s1 + s2 paste(s1, s2) or paste0(s1, s2)
Upper/Lower Case s.upper(), s.lower() toupper(s), tolower(s)
Finding Substrings "World" in s, s.find("World") grepl("World", s), grep("World", s)
Replace Substring s.replace("old", "new") gsub("old", "new", s)
Splitting s.split(" ") (default: whitespace) strsplit(s, " ")(default: whitespace)

10.8 Practice exercises

10.8.1 Practice exercise 1

Try converting the following Python string operations into equivalent R code:

s = "Data Science"
print(len(s))
print(s[5:])
print(s.replace("Data", "AI"))

10.8.2 Practice exercise 2

Define a character and count the number of ts.

char_vec <- 'Getting a tatto is not a nice experience'
#Initializing a variable 'count_t' which will store the number of 't's in the string
count_t <- 0

#Iterating over the entire length of the string. 
#The length of the string is given by the len() function
for (i in 1:nchar(char_vec)) {
  if (substr(char_vec, i, i) == 't') {
    count_t <- count_t + 1
  }
}
print(paste("Number of 't's in the string = ", count_t))
[1] "Number of 't's in the string =  6"

Use strsplit() to implement this function.

10.8.3 Practice exercise 3

Write a program that prints the number of ’the’s found in sentence

sentence <- "She sells the sea shells on the sea shore during the summer"
count <- 0
for (i in 1:(nchar(sentence) - nchar("the"))) {
  if (substr(sentence, i, i + nchar("the") - 1) == "the") {
    count <- count + 1
  }
}
print(paste("Number of thes in the sentence = ", count))
[1] "Number of thes in the sentence =  3"

Use strsplit() to implement this function

10.8.4 Practice exercise 4

10.8.4.1 Problem 1

my_num <- "0"

Using my_num above:

  • check if the number is numeric
  • convert the number to numeric

10.8.4.2 Problem 2

  • Define a variable to be your name.

  • Define a variable to be your favorite number.

  • Define a variable to be your favorite color.

  • Print a sentence that reads: “My name is {} and my favorite number is {}”.

  • Store a variable that checks if your favorite number is less than 10. Print this variable.

  • Store a variable that checks if your favorite number is even. Print this variable.

  • Store a variable that checks if your favorite color is “red”. Print this variable.

  • Convert one of your stored Boolean to a numeric data type. What happens?

  • Print a statement that returns TRUE if your favorite number is less than 10 and favorite color is NOT red and returns FALSE otherwise.

  • Print a statement that return TRUE if your favorite number is even or less than 10.

10.8.5 Practice exercise 5

Create an interactive R code block that asks the user to enter their age and ensures the input is a valid integer. The code should handle incorrect inputs and guide the user until they provide a valid response.

Requirements

  • The script should continuously prompt the user until they enter a valid integer.
  • If the input is not an integer, the script should display an error message and ask again.
  • Once a valid integer is entered:
    • If the age is 18 or older, display: "You are an adult."
    • If the age is less than 18, display: "You are a minor."

Guidelines & Hints

  • Use readline() to collect user input.
  • Convert the input using as.integer() and check if it returns NA for invalid inputs.
  • Utilize a loop to ensure the user is repeatedly prompted until they enter a valid integer.
  • Provide clear error messages to guide the user.

Example User Interaction

Input Output
"abc" "Please enter a valid integer for age."
"twenty" "Please enter a valid integer for age."
"18" "You are an adult."
"17" "You are a minor."