I have a vector of zeros and ones, for example:
x <- c(0,0,1,1,1,0,0,0,0,0,1,1,1,0,0,1)
I need to convert this vector to another form:
c(0,0,1,1,1,0,0,0,0,2,2,2,0,0,3)
where subsequent natural numbers are going to indicate number of block of 'ones' from original vector in positions of that block. Basically I need solution which will compute fast ( x vector will be typically at least >30k long and there will be a multiple vectors like this in one run).
Any ideas that don't involve 'for' loops?
This seems about as quick as I can find. All the options presented in this and @akrun's answer will be fractions of seconds for all but the most huge vectors.
replace(x, x!=0, cumsum(diff(c(0,x)==1)[x!=0]) )
# [1] 0 0 1 1 1 0 0 0 0 0 2 2 2 0 0 3
And a further, possibly pointless way to do it:
replace(x, x!=0, factor(cumsum(x==0)[x!=0]) )
# [1] 0 0 1 1 1 0 0 0 0 0 2 2 2 0 0 3
We can use rle
inverse.rle(within.list(rle(x), values[values!=0] <- seq_along(values[values!=0])))
#[1] 0 0 1 1 1 0 0 0 0 0 2 2 2 0 0 3
Another option is rleid
from data.table
library(data.table)
cumsum(!duplicated(rleid(x)) & x!=0)*x
#[1] 0 0 1 1 1 0 0 0 0 0 2 2 2 0 0 3
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With