tags:

views:

212

answers:

1

I was wondering whether it is possible to use the lapply() function to alter the value of the input, similar to:

a1<-runif(100)
a2<-function(i){
a1[i]<-a1[i-1]*a1[i];a1[i]
}
a3<-lapply(2:100,a2)

I'm looking for something akin to a for() loop, but using the lapply() infrastructure. I haven't been able to get rapply() to do this.

The reason is that the "real" a2 function is a difficult function that only needs to be evaluated if the value of a1[i-1] meets some criteria.

re-phrasing: so i'm trying to replace the for() in the code below by a lapply()-type thing:

    a1<-runif(100)
    a2<-function(i, a1){
        a1[i]<-a1[i-1]*2
        a1[i]
    }
    a3<-as.numeric(lapply(2:100, a2, a1=a1))
#compare the output of a3 with that of a1 after the recursive loop
    a2<-a1 #saved for comparison
    for(i in 2:length(a1)){
        a1[i]<-a1[i-1]*2
    }
cbind(a1[2:100],a3)
#actually this is would be like writting a lapply() version of the cumprod() function
cbind(a1,cumprod(a2))

The R mailing list has advised looking unto the Reduce() function....as in:

a1<-runif(100)
cadd<-function(x) Reduce("*", x, accumulate = TRUE)
cadd(a1)

which gives the same result as cumprod(a1)...but is even slower than the loop:

a1<-runif(100000)
cadd<-function(x) Reduce("*", x, accumulate = TRUE)
looop<-function(a1){
j<-length(a1)
    for(i in 2:j){
     a1[i]<-a1[i-1]*a1[i]
    }
a1
}

> system.time(cadd(a1))
   user  system elapsed 
  1.344   0.004   1.353 
> system.time(cumprod(a1))
   user  system elapsed 
  0.004   0.000   0.002 
> system.time(loop(a1))
   user  system elapsed 
  0.772   0.000   0.775 
>

Any idea ?

+1  A: 

Edit: Following your clarification: no, I don't believe that you can use an apply function to do something recursively like that. The whole point of an apply function is that it applies across the vector/matrix at the same time.

You may also want to look at this related question on stackoverflow.

My old answer:

Try this:

a1<-runif(100)
a2<-function(i, a1){
    a1[i]<-a1[i-1]*a1[i]
    a1[i]
}
a3 <- as.numeric(lapply(2:100, a2, a1=a1))

Unlike a for loop, you need to pass in a reference to anything that you need within an lapply. The return is also a list, so you need to cast it back into whatever form you want.

You might also want to look at the plyr package for easy ways to do this kind of thing.

Beyond that, you can do your operation without a loop:

a3 <- a1[-length(a1)] * a1[-1]

In other words, these statements are completely equivalent:

> all((a1[-length(a1)] * a1[-1]) == as.numeric(lapply(2:100, a2, a1=a1)))
[1] TRUE

But the first version is preferable since it has no iterations.

Shane
nop: i didn't made myself clear. See re-phrasing above :)