Skip to content

Functions and Functional Programming Interview Questions for R Programming

25 Functions and Functional Programming questions with answers for r programming roles — 6 easy, 12 medium, 7 hard.

About Functions and Functional Programming

Writing clean, reusable R code means mastering functions, control flow, error handling, the purrr map family, closures and debugging. This topic also covers input validation, pure functions, memoisation, parallel processing with future and furrr, and when to use Rcpp. These skills separate script writers from developers who build reliable analysis code.

Sheet progressStart practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
3 questions free Unlock the rest in seconds
01

How do you write a function in R with default arguments?

Save to ▾
Show answer
A function is created with the function keyword and returns the value of its last expression, or an explicit return(). gst_price <- function(price, rate = 0.18, round_to = 2) { if (!is.numeric(price)) stop('price must be numeric') round(price * (1 + rate), round_to) } gst_price(1000) # 1180 gst_price(1000, rate = 0.05) gst_price(c(100, 250)) # vectorized
02

What is the difference between if, ifelse() and dplyr's if_else()?

Save to ▾
Show answer
if is a control-flow statement that checks a single TRUE or FALSE value and runs one branch, used for program logic. ifelse() is vectorized and returns a vector of the same length as the condition, used for transforming data. dplyr::if_else() is a stricter vectorized version that requires both outputs to have the same type, preserves classes like dates and has a missing argument for NA conditions, making it safer than ifelse().
03

Explain for, while and repeat loops in R.

Save to ▾
Show answer
A for loop iterates over elements of a vector, for (i in seq_along(x)), and is used when the number of iterations is known. A while loop runs while a condition stays TRUE, useful for convergence or polling. repeat runs indefinitely until break is called. next skips to the next iteration. In R, loops are fine when each iteration is heavy, but for element-wise work vectorized functions or purrr::map() are usually faster and cleaner.
04

Write a recursive function in R to calculate factorial and Fibonacci numbers.

Save to ▾
Show answer
A recursive function calls itself with a smaller input and needs a base case. fact <- function(n) { if (n <= 1) return(1) n * fact(n - 1) } fact(5) # 120 fib <- function(n) { if (n <= 2) return(1) fib(n - 1) + fib(n - 2) } fib(10) # 55 # vectorized and efficient alternative factorial(5); cumprod(1:5)
05

How does the switch() function work in R?

Save to ▾
Show answer
switch() selects one of several alternatives based on a value, which is cleaner than a long chain of if-else statements. With a character input, it matches names: switch(type, mean = mean(x), median = median(x), stop('Unknown type')). The final unnamed argument acts as the default. Empty arguments fall through to the next value, so switch(x, a = , b = 'AB') returns 'AB' for both. It is not vectorized, so use it for single values.
06

Describe a time you learned something from a teammate.

Save to ▾
Show answer
Situation: during my final-year project, our group's R code ran very slowly on a large dataset. Task: I was responsible for the cleaning step. Action: a teammate showed me how to replace my nested for loops with vectorized dplyr operations and explained why loops were slow. I practised the approach on other parts of the code. Result: processing time fell from twenty minutes to under one, and I shared the lesson with the rest of the group.
07

How do you handle errors in R code?

Save to ▾
Show answer
tryCatch() catches errors and warnings so a script can recover or log them; finally runs cleanup. read_safe <- function(path) { tryCatch({ readr::read_csv(path, show_col_types = FALSE) }, warning = function(w) { message('Warning in ', path, ': ', conditionMessage(w)) NULL }, error = function(e) { message('Failed: ', path, ' - ', conditionMessage(e)) NULL }, finally = message('Done: ', path)) }
08

What does the ... (dots) argument do in an R function?

Save to ▾
Show answer
The dots let a function accept any number of additional arguments and pass them on to another function. For example, my_plot <- function(df, ...) ggplot(df, aes(x, y)) + geom_point(...) lets callers pass colour or size without declaring them. You can capture dots with list(...) or count them with ...length(). The downside is that misspelled argument names are silently ignored, so document them and validate with rlang::check_dots_used() in packages.
09

What is the purrr map family?

Save to ▾
Show answer
purrr's map() applies a function to each element of a list or vector and always returns a list. Typed variants return specific types: map_dbl(), map_chr(), map_lgl() and map_int(), and they error if a result has the wrong type, which is safer than sapply(). map2() iterates over two inputs, pmap() over many, and walk() is used for side effects like saving files. Formula shortcuts such as ~ .x * 2 keep code short.
10

Write code using map2() and pmap() to iterate over multiple inputs.

Save to ▾
Show answer
map2() pairs two vectors and pmap() takes a list or data frame of arguments. library(purrr) prices <- c(100, 250, 400) qty <- c(2, 1, 5) map2_dbl(prices, qty, ~ .x * .y) # 200 250 2000 params <- tibble::tibble( region = c('North', 'South'), year = c(2025, 2026) ) pmap(params, function(region, year) { build_report(region = region, year = year) }) walk2(plots, paths, ~ ggsave(.y, .x))
11

How do you validate inputs inside an R function?

Save to ▾
Show answer
Fail early with clear messages using stopifnot(), stop() and match.arg(). summarise_kpi <- function(df, metric = c('revenue', 'orders', 'aov'), min_date = NULL) { stopifnot(is.data.frame(df), nrow(df) > 0) metric <- match.arg(metric) if (!is.null(min_date) && !inherits(min_date, 'Date')) { stop('min_date must be a Date', call. = FALSE) } required <- c('date', metric) missing <- setdiff(required, names(df)) if (length(missing)) stop('Missing columns: ', toString(missing)) # ... compute }
12

Your function gives correct results when you test it but wrong results in the main script. What could be the cause?

Save to ▾
Show answer
A common cause is that the function reads a variable from the global environment instead of taking it as an argument. During testing that global variable had one value, and in the main script it has another. Lexical scoping finds it silently. I would check the function body for names not defined as arguments or locally, for example using codetools::findGlobals(fn), and pass everything explicitly so the function is self-contained.
13

How do you debug an R function?

Save to ▾
Show answer
After an error, traceback() shows the call stack so I can see which function failed. I insert browser() inside a function to pause execution and inspect variables interactively, stepping with n and continuing with c. debug(fn) or debugonce(fn) enters the browser on the next call without editing code. options(error = recover) lets me choose a frame to inspect after an error. RStudio breakpoints offer the same features visually.
14

Your function fails with 'the condition has length > 1' when given a vector. What is wrong?

Save to ▾
Show answer
An if statement can only check a single TRUE or FALSE value, and since R 4.2 a longer condition is an error. The function was written for one value but received a vector. I would replace if with a vectorized alternative such as ifelse(), dplyr::if_else() or case_when(). If the function is truly meant for single values, I validate the input length with stopifnot(length(x) == 1) or apply it over elements with purrr::map().
15

What is a pure function and why prefer them in data pipelines?

Save to ▾
Show answer
A pure function always returns the same output for the same inputs and has no side effects, such as modifying global variables, writing files or printing. Pure functions are easy to test, reuse, cache and run in parallel, because they do not depend on hidden state. In data pipelines, I keep transformations pure, taking a data frame and returning a new one, and isolate side effects such as reading and writing in a few clearly named functions.
16

The same 40 lines of cleaning code are copied into ten scripts. What would you do?

Save to ▾
Show answer
I would extract the logic into well-named functions with arguments for the parts that differ, then move them into one shared file loaded with source() or, better, a small internal R package. A package gives documentation with roxygen2, tests with testthat and versioning, so every script uses the same tested logic. Fixing a bug then happens in one place. I would migrate the scripts gradually and compare outputs to confirm nothing changed.
17

What is the difference between errors, warnings and messages in R?

Save to ▾
Show answer
An error, raised with stop(), halts execution because something cannot continue. A warning, raised with warning(), lets code continue but signals a possible problem, such as NAs introduced by coercion. A message, from message(), is informational, such as progress updates. Messages go to stderr, so they can be suppressed with suppressMessages() without hiding results. Use print() or cat() for output the user requested, not for diagnostics.
18

Tell me about feedback you received in a code review and what you changed.

Save to ▾
Show answer
Situation: in my first quarter, a senior reviewed my R reporting script. Task: address the review comments. Action: the main feedback was that my 300-line script mixed data loading, cleaning and plotting with repeated code. I split it into small functions, added input checks and moved constants to a config file. Result: the next report took half the time to build, and I now structure every new script this way from the start.
19

What are closures and function factories in R?

Save to ▾
Show answer
A closure is a function that remembers the environment in which it was created. A function factory is a function that returns such functions. For example, power <- function(exp) function(x) x^exp; square <- power(2) creates a function that remembers exp = 2. They are useful for creating families of related functions, counters and memoised functions. Because of lazy evaluation, call force(exp) inside the factory so the value is captured immediately.
20

A loop calls an external API 5,000 times and crashes at call 3,200. How do you make it robust?

Save to ▾
Show answer
I wrap each call with purrr::safely() or tryCatch() so one failure does not stop the loop, and add retries with exponential backoff, which httr2 supports through req_retry(). I respect rate limits with Sys.sleep() or req_throttle(). I save results incrementally, for example every 100 calls to an RDS file or database, so a restart resumes from the last checkpoint. Finally I log failed IDs and rerun only those.
21

How do you run R code in parallel?

Save to ▾
Show answer
The parallel package ships with R: mclapply() forks processes on Linux and macOS, while parLapply() uses a socket cluster that also works on Windows. The future framework gives a cleaner interface where you choose a plan, such as plan(multisession), and then use future_map() from furrr or future_lapply(). Parallelism helps when each task is independent and heavy, such as model fitting per group, but adds overhead for small tasks and multiplies memory use.
22

A simulation loop runs for 40 minutes. How would you speed it up?

Save to ▾
Show answer
First I profile with profvis to find the slow lines. Then I try vectorizing, for example generating all random numbers at once with rnorm(n * reps) and using matrix operations instead of nested loops. I preallocate outputs instead of growing them. If iterations are independent, I run them in parallel with future and furrr. If a tight loop cannot be vectorized, I rewrite it in C++ with Rcpp, which often gives a 10 to 100 times speed-up.
23

What is Rcpp and when would you use it?

Save to ▾
Show answer
Rcpp is a package that lets you write C++ functions and call them from R with almost no boilerplate, using cppFunction() for small snippets or sourceCpp() for files. It is used when R code has loops that cannot be vectorized, such as recursive calculations, simulations with dependence between steps or custom algorithms. Many popular packages, including dplyr and data.table internals, rely on compiled code. Use it only after profiling shows a real bottleneck.
24

How do you use Reduce(), Filter() and Map() in base R?

Save to ▾
Show answer
These higher-order functions come from functional programming. nums <- 1:10 Filter(function(x) x %% 2 == 0, nums) # even numbers Map(function(a, b) a + b, 1:3, 4:6) # list: 5 7 9 Reduce(`+`, 1:5, accumulate = TRUE) # 1 3 6 10 15 # join many data frames on a common key dfs <- list(sales, targets, regions) Reduce(function(x, y) merge(x, y, by = 'region_id'), dfs) # purrr equivalents: keep(), map2(), reduce()
25

A function that looks up exchange rates is called thousands of times with the same inputs and is slow. How do you fix it?

Save to ▾
Show answer
The function repeats expensive work for identical inputs, so I would cache its results with memoisation. The memoise package wraps a function, memo_rate <- memoise::memoise(get_rate), and stores results by argument values, returning cached answers instantly. I can set a cache that expires, for example daily for rates, or store it on disk with cachem so it survives sessions. Alternatively I fetch all needed rates once and join them as a lookup table.

Frequently asked questions

How important is Functions and Functional Programming in R Programming interviews?

Writing clean, reusable R code means mastering functions, control flow, error handling, the purrr map family, closures and debugging. This topic also covers input validation, pure functions, memoisation, parallel processing with future and furrr, and when to use Rcpp. These skills separate script writers from developers who build reliable analysis code.

How should I use the Functions and Functional Programming sheet?

Go top to bottom — easy to hard. Answer before opening each answer, tick what you solved and save misses to Last-Minute Revision.