2

您好我正在尝试将以下递归伪代码定义转换为 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 的一个答案)。

4

3 回答 3

4

您可以使用带有累积选项的 Reduce 函数来保存所有中间值。

要了解它是如何工作的,请在简单的“sum”函数上尝试一下

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)
于 2013-03-19T19:01:41.760 回答
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

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

于 2013-03-19T18:24:00.543 回答
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_samplefor 循环来解决问题。这使得当前值和先前值之间的关系变得明确:

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 循环并将其替换为函数式. 不幸的是,没有封装此模式的内置函数,因此您可以编写自己的(如果这是代码中非常常见的模式,这是一个好主意),或者坚持使用 for 循环(如果您愿意,这是个好主意您的代码易于阅读)。

于 2013-03-20T13:12:11.410 回答