Write a function

Author

Aurélien Ginolhac

Published

March 26, 2025

Objective

Write a for loop and understand it focuses on the iteration and not actions

Report AI usage!

If you use any AI tool, report its name and associated prompts next to your answers.

Any obvious AI answers un-flagged as such will not be considered.

Take 5 min to watch this video by Hadley Wickham, until 5 min.

Being lazy, instead of you doing the work, rely on the work of someone else | Hadley Wickham

Aim: write a function that takes a vector as an argument and returns if they are even numbers.

For example, passing the vector c(1, 3, 2, 4) to the function is_even() should output:

is_even(c(1, 3, 2, 4))
[1] FALSE FALSE  TRUE  TRUE
Write the pseudocode

The structure

  • Here we would like to introduce the use of different programming statements you learned, such as if, else if, else or a for loop.
  • Write, in human terms (or pseudocode), how the function could be constructed
  1. Initialize a res vector with logicals
  2. For each element of the argument
  3. Test if the element is an even number
  4. Return res

Do it using R

Version 0, not in a function

Start by writing a piece of code that does the job, following the steps of your pseudocode

# test vector named a
x <- c(1, 3, 2, 4)
# initialized a vector at 0
res <- vector(mode = "logical", length = length(x))
for (i in x) { # iterate all elements, R will do from 1 to length(x)
  res[i] <- x[i] %% 2 == 0  # %% is the modulo operator
}
res
[1] FALSE FALSE  TRUE  TRUE
Convert your functional piece of code as a function named is_even()
Tip
  • Remember that function arguments are then local to the function’s environment
  • Remember the modulo operation is a %% b in R and returns the remainder of the division of a/b. If b = 2 and the result is different from zero, then a is an odd number.
  • Remember to test if a equals b using == and not =. a = b is an assignment leading a to take the value of b!
  • Returning the expected value, should be placed outside the for loop
x <- c(1, 3, 2, 4)
is_even <- function(x) {
  res <- vector(mode = "logical", length = length(x))
  for (i in x) { # iterate all elements, R will do from 1 to length(x)
    res[i] <- x[i] %% 2 == 0  # %% is the modulo operator
  }
  res
}
is_even(x)
[1] FALSE FALSE  TRUE  TRUE
Defensive programming, sanity check.

What would happen if we provide some characters, or a matrix, as an input to is_even()? Is your function able to deal with such an input?

No, but it should. Add a test before doing anything else to check if numbers are provided to the function.

Tip

The R code:

stop("Warning! some conditions are not fulfilled to continue bla bla \n")

should help. It stops the execution and print the chosen message. To prevent a chunk to stop the rendering with a desired error, use the option

#| error: true
x <- c(1, 3, 2, 4)

is_even <- function(x) {
  # if the input is not numeric, we stop the code execution
  # of note, the call. = FALSE is to avoid printing the code line, makes the error more explicit
  if (!is.numeric(x)) stop("input not numeric!", call. = FALSE)
  if (length(x) == 0) stop("input cannot be empty!", call. = FALSE)
  res <- vector(mode = "logical", length = length(x))
  for (i in x) { # iterate all elements, R will do from 1 to length(x)
    res[i] <- x[i] %% 2 == 0  # %% is the modulo operator
  }
  res
}
is_even(x)
[1] FALSE FALSE  TRUE  TRUE
is_even("a")
Error: input not numeric!
is_even(double(0))
Error: input cannot be empty!

Vectorization

Now that the for loop was a pain to set-up, we can use what is good at: vectorization

Replace all the for loop code with one line of vectorization
is_even <- function(x) {
  if (!is.numeric(x)) stop("input not numeric!", call. = FALSE)
  # the vector is integer divided by 2, the iteration is transparent
  # then logical test: is different from 0
  # finally sum up the logical vector, TRUE is 1, FALSE is 0
  x %% 2 == 0
}

is_even(x)
[1] FALSE FALSE  TRUE  TRUE

Refinements

Create a new function that returns the number of even items

Such as:

count_even(c(1, 3, 3, 4))
[1] 1
count_even(c(1, 3, 3, 4, 4))
[1] 2
Modify again the function so it returns the sum of even items

Such as:

sum_even(c(1, 3, 3, 4))
[1] 4
sum_even(c(1, 3, 3, 4, 4))
[1] 8