Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vectorizing loop over vector elements

I find it hard to come up with a fast solution to the following problem:

I have a vector of observations, which indicates the time of observation of certain phenomena.

example <- c(0,0,0,1,0,1,1,0,0,0,-1,0,0,-1,-1,0,0,1,0,0);

Now I would like to eliminate zeros between particular observations, given that a certain phenomenon is assumed to continue until a contradictory observation is noted, i.e., if ''1'' was observed in third observation, I would like to have only ''1'' up to 11th element, when first ''-1'' is observed. So my desired output looks like:

desired.output <- c(0,0,0,1,1,1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,1,1,1);

> print(cbind(example, desired.output))
      example desired.output
 [1,]       0              0
 [2,]       0              0
 [3,]       0              0
 [4,]       1              1
 [5,]       0              1
 [6,]       1              1
 [7,]       1              1
 [8,]       0              1
 [9,]       0              1
[10,]       0              1
[11,]      -1             -1
[12,]       0             -1
[13,]       0             -1
[14,]      -1             -1
[15,]      -1             -1
[16,]       0             -1
[17,]       0             -1
[18,]       1              1
[19,]       0              1
[20,]       0              1

My lame solution is

for (i in 1:length(example)){
     if (example[i] != 0){
       current <- example[i];
       while ((example[i] != -current) & (i <= length(example))){
         example[i] <- current;
         i <- i+1;
       }
    }
}

I will appreciate any help with speeding this up.

like image 322
Banach Avatar asked Jun 11 '14 08:06

Banach


1 Answers

I'll try to be the one to offer a pure R solution:

example <- c(0,0,0,1,0,1,1,0,0,0,-1,0,0,-1,-1,0,0,1,0,0);

cs = cumsum(example!=0);
mch = match(cs, cs);
desired.output = example[mch];

print(cbind(example,desired.output))

UPD: It may be faster to calculate mch above with

mch = findInterval(cs-1,cs)+1

UPD2: I like the answer by @Roland. It can be shortened to two lines:

NN = (example != 0);
desired.output = c(example[1], example[NN])[cumsum(NN) + 1L];
like image 116
Andrey Shabalin Avatar answered Sep 23 '22 21:09

Andrey Shabalin