Reputation: 4513
I have a logical vector
v <- c(FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE)
I want to count the number of FALSE
between each TRUE
. For the above example, the desired results is
3 2 1 4
Ideally, the answer would not use an iterative approach. My actual application is a much larger logical vector. The more efficient the better.
Thanks!
Upvotes: 1
Views: 1248
Reputation: 14842
Although the matter is already settled, here is a C++ function that will boost it a bit further too, although being a bit cumbersome to write.
require(Rcpp)
require(inline)
cpp.fun <- cxxfunction(signature(x="logical"), plugin="Rcpp", body='
int n = LENGTH(x);
Rcpp::IntegerVector lengths(n);
int count = 0;
for(int i = 0; i < n; i++){
if(!LOGICAL(x)[i]){
lengths[count]++;
} else {
count++;
}
}
lengths = Rcpp::head(lengths, count);
return(lengths);
')
v <- runif(10000000) > .8
require(microbenchmark)
microbenchmark(a = with(rle(v), lengths[!values]),
b = diff(which(c(TRUE, v))) - 1,
c = cpp.fun(v))
Unit: milliseconds
expr min lq mean median uq max neval
a 479.59042 543.26234 585.36910 558.24042 605.80794 863.5284 100
b 75.82237 81.25428 103.31213 87.55149 131.09488 219.2535 100
c 42.01732 44.69037 50.14274 45.80284 47.67927 102.3952 100
Upvotes: 2
Reputation:
You can use rle
function, such as:
out <- rle(v)
out$lengths[!out$values]
# [1] 3 2 1 4
Associated with the with
function:
with(out, lengths[!values])
# [1] 3 2 1 4
Upvotes: 5