Есть несколько способов сделать это (это поможет, если вы предоставите getNewVal
)
1. С помощью Reduce
Ваша задача сводится к x_n+1 = f(x_n); x_0 = const.
Это типичный вариант использования для reduce
:
# Reduce
func_Reduce <- function (n, p, val) Reduce(function (x,y) getNewVal(p = p, val = x),
x = 1:n, init = val, accumulate = TRUE)
2. Использование семейства применения
Вот решение с использованием vapply
из семейства применения
# Apply
func_vapply <- function (n, p, val) vapply(0:n,
function(i, p, val){
if (i == 0) {
vals <<- val # overwrites in the func. env.
return (val)
}
newVal <- getNewVal(p, val = vals[length(vals)])
vals <<- c(vals, newVal) # overwrites in the func. env.
return(newVal)
}, numeric(1), p = p, val = val)
Здесь нужно использовать <<-
, чтобы отслеживать последний элемент vals
.
3. Использование рекурсии
Эту задачу также можно выполнить с помощью рекурсии
# Recursion
func_recursive <- function(n, p, val){
if (n == 0) return (val)
vals <- func_recursive (n-1, p, val)
newVal <- getNewVal(p, val = vals[length(vals)])
c(vals, newVal)
}
Хотя рекурсии следует использовать с определенной осторожностью.
Примеры
Вот пример:
# Dummy function
getNewVal <- function (p, val) val %/% p
# Arguments
n <- 17
p <- 3
val <- 45459748
# Examples
func_Reduce(n = n, p = p, val = val)
func_vapply(n = n, p = p, val = val)
func_recursive(n = n, p = p, val = val)
# all yielding
# [1] 45459748 15153249 5051083 1683694 561231 187077 62359 20786 6928 2309 769 256 85 28 9 3 1 0
# benchmarking
microbenchmark::microbenchmark(func_Reduce(n = n, p = p, val = val),
func_vapply(n = n, p = p, val = val),
func_recursive(n = n, p = p, val = val)
)
# Unit: microseconds
# expr min lq mean median uq max neval cld
# func_Reduce(n = n, p = p, val = val) 25.163 26.257 28.65292 26.986 27.3515 82.417 100 a
# func_vapply(n = n, p = p, val = val) 30.268 30.998 32.82484 31.363 32.4570 80.958 100 b
# func_recursive(n = n, p = p, val = val) 23.339 24.798 27.16511 25.527 26.2570 82.417 100 a