CindyLhasapoo
CindyLhasapoo

Reputation: 45

Count the number of consecutive TRUE values in R

I would like to count how many times I see two consecutive TRUE values in R. For example,

x <- c(T,F,T,T,F,F,T,F,T,F)
x
 [1]  TRUE FALSE  TRUE  TRUE FALSE FALSE  TRUE FALSE  TRUE FALSE

It would count 1 since there is a TRUE at position 3 and TRUE at position 4. If there are more than 2 consecutive TRUE, then I just want to count it only once, ie this vector

x <- c(T,F,T,T,T,F,T,F,T,F)
x
 [1]  TRUE FALSE  TRUE  TRUE TRUE FALSE  TRUE FALSE  TRUE FALSE

would still count 1. I started with looking at rle() but I got stuck. Any help would be greatly appreciated. Thanks!

Upvotes: 3

Views: 3820

Answers (3)

akrun
akrun

Reputation: 886968

Here is another option with rleid from data.table. The rleid gives a unique id to adjacent elements that are different, multiply with x, to convert the elements that corresponds to the FALSE in original vector to 0, get the frequency with tabulate convert to a logical vector (==2) and get the sum.

library(data.table)
sum(tabulate(rleid(x)*x)==2)
#[1] 1

Upvotes: 0

989
989

Reputation: 12937

You could also use cumsum and split for that purpose as follows:

x <- c(TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, 
       TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE)
sum(lapply(split(x, cumsum(!x)), sum)>=2)
#[1] 3

Upvotes: 1

Carles Mitjans
Carles Mitjans

Reputation: 4866

This should work:

with(rle(x), sum(lengths[values] >= 2))

Explanation:

As you are using Booleans, you can take profit of it. rle(x)$lengths will return how many consecutive times TRUE or FALSE happen in the vector. Example

x <- c(T,F,T,T,T,F,T,F,T,F,T,T)
rle(x)$lengths
[1] 1 1 3 1 1 1 1 1 2

Now you only want those values in this vector that correspond to TRUEs. rle(x)$values returns a vector with the order of appearance. Example:

rle(x)$values
[1]  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE

You can use this to only get the TRUEs in the lengths vector:

rle(x)$lengths[rle(x)$values]
[1] 1 3 1 1 2

And the last step should be obvious: count how many of this values are grater or equal than 2. All together (with performance improvement):

with(rle(x), sum(lengths[values] >= 2))
[1] 2

Upvotes: 11

Related Questions