Cut elements from the beginning and end of an R vector

Viewed 492

For time series analysis I handle data that often contains leading and trailing zero elements. In this example, there are 3 zeros at the beginning an 2 at the end. I want to get rid of these elements, and filter for the contents in the middle (that also may contain zeros)

vec <- c(0, 0, 0, 1, 2, 0, 3, 4, 0, 0)

I did this by looping from the beginning and end, and masking out the unwanted elements.

mask <- rep(TRUE, length(vec))

# from begin
i <- 1
while(vec[i] == 0 && i <= length(vec)) {
  mask[i] <- FALSE
  i <- i+1
}

# from end
i <- length(vec)
while(i >= 1 && vec[i] == 0) {
  mask[i] <- FALSE
  i <- i-1
}

cleanvec <- vec[mask]
cleanvec
[1] 1 2 0 3 4

This works, but I wonder if there is a more efficient way to do this, avoiding the loops.

3 Answers
vec[ min(which(vec != 0)) : max(which(vec != 0)) ]

Basically the which(vec != 0) part gives the positions of the numbers that are different from 0, and then you take the min and max of them.

We could use the range and Reduce to get the sequence

vec[Reduce(`:`, range(which(vec != 0)))]
#[1] 1 2 0 3 4

Take the cumsum forward and backward of abs(vec) and keep only elements > 0. if it were known that all elements of vec were non-negative, as in the question, then we could optionally omit abs.

vec[cumsum(abs(vec)) > 0 & rev(cumsum(rev(abs(vec)))) > 0]
## [1] 1 2 0 3 4
Related