Reputation: 781
I have a pretty straightforward problem which is giving me grief despite a couple of hours of hair-wringing, so I thought I'd ask your help. I am looking for a straightforward way to return a vector which contains only the last element of some original vector.
This is my original vector, 'a':
a<-c(0,0,1,0,0,1,0,0,1,0)
I want to produce the vector 'b', which is of the same length as 'a', and carries only its last nonmissing element. In other words,
b = (0,0,0,0,0,0,0,0,1,0)
I have been able to do this by building a loop running backwards from the end of vector 'a' to its first element, but that seems decidedly inelegant. I'm sure there's a better way.
In case anyone is curious, the larger issue: I am trying to change a value of one vector where it corresponds to the last nonmissing element of another vector.
Thanks very much for any help.
Upvotes: 6
Views: 236
Reputation: 49448
Another simple option:
n = max(which(as.logical(a))) - 1
c(numeric(n), tail(a, -n))
Upvotes: 3
Reputation: 44614
I'm a little late, but here's another option:
a[head(which(a == 1), -1)] <- 0
or
replace(a, head(which(a == 1), -1), 0)
Benchmarks
Unit: milliseconds
expr min lq median uq max neval
akrun() 8.600 9.201 11.346 12.531 68.45 100
plourde() 9.034 9.767 11.545 12.498 69.33 100
flick() 164.792 215.759 221.868 227.237 333.72 100
thomas() 4.210 6.427 8.108 9.913 66.65 100
Functions
akrun <- function() {
b<- numeric(length(a))
b[max(which(a!=0))] <- 1
b
}
plourde <- function() replace(a, head(which(a == 1), -1), 0)
flick <- function() ifelse(cumsum(a)==sum(a), a, 0)
thomas <- function() `[<-`(a, rev(which(as.logical(a)))[-1], 0)
Upvotes: 4
Reputation: 206526
I believe this should work as well
ifelse(cumsum(a)==sum(a), a, 0)
# [1] 0 0 0 0 0 0 0 0 1 0
This assumes that "missing" values are zeros and non-missing values are 1's. If you have values other than 1's, you would do
ifelse(cumsum(a!=0)==sum(a!=0), a, 0)
Upvotes: 6
Reputation: 44555
This is just for fun as a one-liner:
`[<-`(a, rev(which(as.logical(a)))[-1], 0)
## [1] 0 0 0 0 0 0 0 0 1 0
And a slightly different version:
`[<-`(integer(length = length(a)), rev(which(a != 0))[1], 1)
## [1] 0 0 0 0 0 0 0 0 1 0
Upvotes: 7
Reputation: 887741
One option is
b<- numeric(length(a))
b[max(which(a!=0))] <- 1
b
#[1] 0 0 0 0 0 0 0 0 1 0
Upvotes: 5