Suppose I have:
v <- c(1,2,0,0,0,3,4,4,4,0,0,0,0,5,0)
v
[1] 1 2 0 0 0 3 4 4 4 0 0 0 0 5 0
I would like to eliminate any consecutive 0's where the number of consecutive 0's is 2+ (2 or more). So the example above would turn into:
1 2 3 4 4 4 5 0
NOTE: I would prefer a base-R solution but other solutions would be interesting
1) na.locf0 This uses the zoo package but is only one line of code. It makes use of the maxgap argument in na.locf0. Replace each 0 with an NA and everything else with 0. Use na.locf0 with maxgap to fill it in, add it to the original vector, apply na.omit to remove the NAs and use c to remove attributes.
library(zoo)
c(na.omit(na.locf0(ifelse(v == 0, NA, 0), maxgap = 1) + v))
## [1] 1 2 3 4 4 4 5 0
2) rleid This uses rleid from data.table. It is a bit longer than (1) but still reasonably short. It groups the data using rleid and then for each group generates an NA or the original data removing the NAs at the end.
library(data.table)
fun <- function(x) if (x[1] == 0 & length(x) > 1) NA else x
c(na.omit(ave(v, rleid(v), FUN = fun)))
## [1] 1 2 3 4 4 4 5 0
An option with rle. We can create a logical condition with rle and extract the values based on that
with(rle(v), {i1 <- !(values == 0 & lengths > 1); rep(values[i1], lengths[i1])})
#[1] 1 2 3 4 4 4 5 0
Note: In the previous version, the OP' output returned only a single value. We just need to replicate with the lengths using the same logic
Or it can be made more compact with rleid
library(data.table)
v[!(ave(v, rleid(v), FUN = length) > 1 & !v)]
#[1] 1 2 3 4 4 4 5 0
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With