R Tutorial
Fundamentals of R
Variables
Input and Output
Decision Making
Control Flow
Functions
Strings
Vectors
Lists
Arrays
Matrices
Factors
DataFrames
Object Oriented Programming
Error Handling
File Handling
Packages in R
Data Interfaces
Data Visualization
Statistics
Machine Learning with R
Recursive functions are those that call themselves, either directly or indirectly, in order to accomplish a task. They're particularly useful for operations that have a naturally recursive structure, such as traversing tree-like data structures, performing certain mathematical computations, and more.
In this tutorial, we'll introduce recursive functions in R and walk through some basic examples.
A recursive function needs:
A classic example of recursion is the calculation of the factorial of a number. The factorial of a number n is n times the factorial of n−1.
factorial_recursive <- function(n) { # Base case if (n == 0) { return(1) } # Recursive case else { return(n * factorial_recursive(n - 1)) } } print(factorial_recursive(5)) # Outputs 120
Another classic example is the Fibonacci sequence, where each number is the sum of the two preceding ones.
fibonacci_recursive <- function(n) { # Base cases if (n == 0) { return(0) } else if (n == 1) { return(1) } # Recursive case else { return(fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2)) } } print(fibonacci_recursive(10)) # Outputs 55
While recursion can simplify certain problems, it's important to use it judiciously:
Stack Overflow: R has a recursion limit, after which it will throw a "maximum recursion depth exceeded" error. This protects against infinite loops and excessive memory usage.
Efficiency: The Fibonacci example is notoriously inefficient when implemented with pure recursion because it re-computes values multiple times. More efficient solutions use iteration or memoization (caching results).
Let's take a look at a more complicated problem: flattening a nested list.
flatten_list <- function(x) { if (!is.list(x)) { return(list(x)) } else if (length(x) == 0) { return(NULL) } else { return(c(flatten_list(x[[1]]), flatten_list(x[-1]))) } } nested_list <- list(1, list(2, 3, list(4, 5)), 6) print(flatten_list(nested_list))
The function works by checking if the input is not a list (base case) or if it's an empty list. Otherwise, it takes the first element of the list and the rest of the list and flattens both, combining the results.
Recursive functions are a powerful tool, but they should be used with caution. Always ensure you have a clear base case to avoid infinite loops, and be aware that recursive solutions are not always the most efficient ones. If you're dealing with tasks that involve inherently recursive structures or algorithms, recursive functions can be a natural and elegant solution.
R code examples for recursion:
# Simple recursive function to calculate factorial factorial_recursive <- function(n) { if (n == 0 || n == 1) { return(1) } else { return(n * factorial_recursive(n - 1)) } } # Example usage result <- factorial_recursive(5)
Handling base cases in recursive functions in R:
# Example recursive function with base case recursive_sum <- function(n) { if (n == 1) { return(1) } else { return(n + recursive_sum(n - 1)) } }
Factorial and Fibonacci using recursion in R:
# Recursive function for factorial factorial_recursive <- function(n) { if (n == 0 || n == 1) { return(1) } else { return(n * factorial_recursive(n - 1)) } } # Recursive function for Fibonacci fibonacci_recursive <- function(n) { if (n <= 1) { return(n) } else { return(fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2)) } }
R recursive function for tree structures:
# Recursive function for traversing a tree structure traverse_tree <- function(node) { if (!is.null(node)) { cat(node$value, "\n") traverse_tree(node$left) traverse_tree(node$right) } }
Recursive data structures and lists in R:
# Recursive list structure recursive_list <- list(value = 1, next = list(value = 2, next = list(value = 3, next = NULL)))