Reputation: 351
Say I have a logical value like this
rex <- c(TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, NA)
How do I create a counter which will only count for the TRUE
and will group consecutive repetitions as the same value in the counter. ex. to have something like this:
1, NA, 2,2,NA, 3, NA
Upvotes: 2
Views: 84
Reputation: 1327
The accepted solution doesn't work for the following case:
rex <- c(TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, NA, NA, TRUE)
It prints 1 NA 2 2 NA 3 NA NA NA
.
The following function returns the correct answer:
solution <- function (rex) {
result <- c()
counter <- 1
consecutive <- FALSE
for (i in 1:length(rex)) {
if (rex[i] == TRUE && !is.na(rex[i]) && consecutive) {
result <- c(result, counter)
consecutive <- TRUE
} else if (rex[i] == TRUE && !is.na(rex[i]) && !consecutive) {
result <- c(result, counter)
consecutive <- TRUE
} else{
if(i < length(rex) && rex[i+1] == TRUE && !is.na(rex[i+1])){
counter <- counter + 1
}
result <- c(result, NA)
consecutive <- FALSE
}
}
return(result)
}
Calling solution(rex)
prints 1 NA 2 2 NA 3 NA NA 4
, which is the correct answer.
Upvotes: 1
Reputation: 39858
A twist on the answer provided by @Onyambu could be:
with(rle(!is.na(rex) & rex), rep(cumsum(values), lengths)) * rex^NA
[1] 1 NA 2 2 NA 3 NA
It should also work when there are NAs not just at the end of the vector.
Upvotes: 0
Reputation: 79288
You could use rle
and its inverse:
inverse.rle(modifyList(b<-rle(rex),list(values = with(b,cumsum(values)*NA^(!values)))))
[1] 1 NA 2 2 NA 3 NA
This can also be written as:
inverse.rle(`[[<-`(b<-rle(rex),"values",with(b,cumsum(values)*NA^(!values))))
To break it down:
b <- rle(rex)
b$values <- cumsum(b$values) * NA^(!b$values)
inverse.rle(b)
Upvotes: 1