将简单的递归关系转换为功能程序

时间:2013-03-19 17:09:37

标签: r functional-programming

您好我正在尝试将以下递归伪代码定义转换为R中的函数式编程构造:

a = [ random numbers between 0 and 10 ]
b = [ random numbers between -5 and 5 ]
c = [ random numbers between 0 and -10 ]

x0 = 200
index = 0

function f(x) {
    index = index + 1
    if( x is between 200 and 220 ) return f(x + a[index])
    else if(x is between 220 and 250) return f(x + b[index])
    else if(x is 250 and above) return f(x + c[index])
}

可执行R代码是:

a <- sample(1:10,size=50, replace=TRUE)
b <- sample(-5:5,size=50, replace=TRUE)
c <- sample(-1:-10,size=50, replace=TRUE)

index <- 0;


myfunc <- function(x){
  index <<- index + 1;
  if(index == 50) return(x)
  if(x <= 220){ return(myfunc(x + a[index])) }
  else if(x > 220 & x < 250){ return(myfunc(x + b[index])) }
  else {return( myfunc(x + c[index]))}
}
print(myfunc(200));

想讨论任何方法,包括Map / Filter / Reduce或Vectorisation。非常感谢提前。

此外,如何保留50 x元素的整个路径(而不仅仅是查看x的一个答案)。

3 个答案:

答案 0 :(得分:4)

您可以使用Reduce功能和accumulate选项来保存所有中间值。

要了解其工作原理,请尝试使用简单的“总和”功能

x = rep(200, 50)
Reduce(x=x, f=sum) 
Reduce(x=x, f=sum, accumulate=T)

您正在寻找的答案需要您重写您的特殊功能,以便将其传递给Reduce:

foo <- function(x, y = 0){
    if (200 <= x & x < 220){
        x + sample(1:10, 1)
    }
    else if(220 <= x & x < 250){
        x + sample(-5:5, 1)
    }
    else if (250 <= x){
        x + sample(-1:-10, 1)
    }
}

Reduce(x=rep(200, 50), f=foo, accumulate=T)

答案 1 :(得分:3)

我还没有把它变成一种功能形式,但我可以在R中做我认为你想要的东西:

 x=200; index=0; while (index < 50) {index <- index + 1;
    if(tail(x,1) <= 220){ x <-c(x,  tail(x,1)+a[index]) } else
     { if(tail(x,1)  & tail(x,1)  < 250) { x <-c(x , tail(x,1)+b[index]) }  else
        {x <-c( x , tail(x,1)+c[index])} }
  }
 x
 [1] 200 204 206 210 213 215 216 219 227 222 219 220 223 221 224 229 231 227 226 229 224 223 221 221
[25] 216 218 223 220 226 221 217 224 228 228 231 236 233 234 229 227 230 229 227 227 225 225 228 232
[49] 227 230 228

也许这有助于找到一种“功能化”它的方法。我认为Reducereplicate或者参考类对象很有可能提供机制。这只是将x向量扩展1个元素,然后在下一次迭代时使用该元素来选择要使用的增量向量。如果你想要超过50长度输出,你可以使用模数余数数学作为索引。

答案 2 :(得分:2)

首先,我将首先参数化函数以匹配您的原始描述,并在模拟参数发生变化时更容易更改。

foo_cat <- function(x) {
  if (200 <= x & x < 220) return("a")
  if (220 <= x & x < 250) return("b")
  if (250 <= x) return("c")

  stop("x out of range")
}
ranges <- list(a = 1:10, b = -5:5, c = -(1:10))

foo_sample <- function(x, n = 1) {
  sample(ranges[[foo_cat(x)]], n, rep = TRUE)
}

对我而言,这是函数式编程中最重要的部分:编写封装解决方案重要组件的函数。

接下来,我们将使用foo_sample来解决for循环问题。这使得当前值和先前值之间的关系显式:

n <- 50
out <- c(200, rep(NA, n - 1))

for(i in seq(2, n)) {
  out[i] <- out[i - 1] + foo_sample(out[i - 1])
}

接下来,您可以考虑删除for循环并将其替换为functional。不幸的是,没有内置函数来封装这个模式,所以你可以编写自己的函数(如果这是代码中非常常见的模式,这是一个好主意),或者坚持使用for循环(如果你想要一个好主意)你的代码易于阅读)。