Add index to adjacent equal value runs

Is there a faster way to make a counter index than using a loop? Within continuous runs of equal values, the index must be the same. I think the cycle is very slow, especially when the data is so big.

The input and the desired output are shown for illustration.

x <- c(2, 3, 9, 2, 4, 4, 3, 4, 4, 5, 5, 5, 1) 

Desired Result Counter:

 c(1, 2, 3, 4, 5, 5, 6, 7, 7, 8, 8, 8, 9) 

Please note that non-contiguous runs have different indices. For instance. see desired indices of values 2 and 4

My inefficient code:

 group[1]<-1 counter<-1 for (i in 2:n){ if (x[i]==x[i-1]){ group[i]<-counter }else{ counter<-counter+1 group[1]<-counter} } 
+6
source share
3 answers

If you have numerical values ​​like this, you can use diff and cumsum to add changes to the values

 x <- c(2,3,9,2,4,4,3,4,4,5,5,5,1) cumsum(c(1,diff(x)!=0)) # [1] 1 2 3 4 5 5 6 7 7 8 8 8 9 
+7
source

Using data.table , which has the rleid() function:

 require(data.table) # v1.9.5+ rleid(x) # [1] 1 2 3 4 5 5 6 7 7 8 8 8 9 
+8
source

This will work with numeric character values:

 rep(1:length(rle(x)$values), times = rle(x)$lengths) #[1] 1 2 3 4 5 5 6 7 7 8 8 8 9 

You can also be more efficient by calling rle only once (about 2 times faster), and a very small speed improvement can be done using rep.int instead of rep :

 y <- rle(x) rep.int(1:length(y$values), times = y$lengths) 
+6
source

Source: https://habr.com/ru/post/987464/


All Articles