Jacob H
Jacob H

Reputation: 4513

Efficient way of counting `FALSE` between `TRUE`

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

Answers (3)

Backlin
Backlin

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

ExperimenteR
ExperimenteR

Reputation: 4473

diff(which(c(TRUE, v))) - 1

if you seek efficiency.

Upvotes: 5

user3710546
user3710546

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

Related Questions