Practical 1

Iteration with control flow

  1. Write a loop that prints the months of the year (Hint: See month.name).
for (month in month.name) {
  print(month)
}
[1] "January"
[1] "February"
[1] "March"
[1] "April"
[1] "May"
[1] "June"
[1] "July"
[1] "August"
[1] "September"
[1] "October"
[1] "November"
[1] "December"
  1. Update your loop to only print months ending in “y”.

Use str_ends from the stringr package.

library(tidyverse)

for (month in month.name) {
  if (str_ends(month, "y")) {
    print(month)
  }
}
[1] "January"
[1] "February"
[1] "May"
[1] "July"

Our first function

  1. Write a function that calculates the area of a circle. Your function should take a single argument: radius.
area_circle <- function(radius) {
  return(pi * (radius^2))
}

area_circle(12)
[1] 452.3893
  1. Write a function that calculates the area of a rectangle. The function should take two parameters: length and width.
area_rectangle <- function(length, width) {
  return(length * width)
}

area_rectangle(12.5, 8.7)
[1] 108.75
  1. Update your previous answer to check if length and width are positive numbers. If not, the function should return an error message.
area_rectangle <- function(length, width) {
  if(length <= 0 || width <= 0) {
    stop("Length and width must be positive numbers.")
  } else {
  return(length * width)
  }
}
  1. Test your function with invalid input (e.g., -2 for length and 4 for width)
area_rectangle(-2, 4)
  1. Test the function with different data types, like characters or logical values, and observe the output.
area_rectangle("2", 4)
area_rectangle(TRUE, 4)

Plotting function

  1. Write a function that plots a scatterplot for two vectors.
    • Test your function with mtcars$wt and mtcars$mpg.
    • Hint: Use plot(x, y).
plot_xy <- function(x, y) {
  plot(x, y)
}

plot_xy(mtcars$wt, mtcars$mpg)

  1. Update your function to check that the provided vectors:
    1. are numeric;
    2. are the same length.

If not, return an informative error message (Hint: Use stop("...")).

plot_xy <- function(x, y) {
  if (length(x) != length(y)) {
    stop("Vectors must have the same length")
  } else if (!is.numeric(x) | !is.numeric(y)) {
    stop("Vectors must both be numeric")
  }
  plot(x, y)
}
# Testing the function
plot_xy(1:10, letters)   # Error: Vectors must both be numeric
plot_xy(1:26, letters)   # Error: Vectors must both be numeric
plot_xy(1:26, rnorm(26)) # Success: Plots scatterplot

Fizz buzz

Fizz buzz is a word game to teach division. Players take turns to count incrementally, replacing any number divisible by three with the word “fizz”, and any number divisible by five with the word “buzz”, and any number divisible by both 3 and 5 with the word “fizzbuzz”.

Write a fizzbuzz() function, taking a single number as input. The logic of the function is as follows:

  • If the number is divisible by three, it returns “fizz”.
  • If it’s divisible by five it returns “buzz”.
  • If it’s divisible by three and five, it returns “fizzbuzz”.
  • Otherwise, it returns the number.

You can use the modulo operator %% to check for divisibility. For example:

1:10 %% 3 == 0
 [1] FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE
fizzbuzz <- function(x) {
  # Check the input is a single numeric value
  stopifnot(length(x) == 1)
  stopifnot(is.numeric(x))
  if (!(x %% 3) && !(x %% 5)) {
    return("fizzbuzz")
  } else if (!(x %% 3)) {
    return("fizz")
  } else if (!(x %% 5)) {
    return("buzz")
  } else {
    return(as.character(x))
  }
}

Test your function by looping over the numbers 1 to 30 and printing the number and the result at each step.

for (i in seq_along(1:30)) {
  print(paste(i, fizzbuzz(i)))
}
[1] "1 1"
[1] "2 2"
[1] "3 fizz"
[1] "4 4"
[1] "5 buzz"
[1] "6 fizz"
[1] "7 7"
[1] "8 8"
[1] "9 fizz"
[1] "10 buzz"
[1] "11 11"
[1] "12 fizz"
[1] "13 13"
[1] "14 14"
[1] "15 fizzbuzz"
[1] "16 16"
[1] "17 17"
[1] "18 fizz"
[1] "19 19"
[1] "20 buzz"
[1] "21 fizz"
[1] "22 22"
[1] "23 23"
[1] "24 fizz"
[1] "25 buzz"
[1] "26 26"
[1] "27 fizz"
[1] "28 28"
[1] "29 29"
[1] "30 fizzbuzz"
  • Does your function work for multiple input values? (e.g., a numeric vector). Why not?
  • Modify your function to accept a numeric vector.