wotuzu17
wotuzu17

Reputation: 157

Cut elements from the beginning and end of an R vector

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.

Upvotes: 5

Views: 793

Answers (3)

G. Grothendieck
G. Grothendieck

Reputation: 269852

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

Upvotes: 0

akrun
akrun

Reputation: 887501

We could use the range and Reduce to get the sequence

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

Upvotes: 0

Ric S
Ric S

Reputation: 9257

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.

Upvotes: 6

Related Questions