daanoo
daanoo

Reputation: 781

Grabbing the last element of a vector

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

Answers (5)

eddi
eddi

Reputation: 49448

Another simple option:

n = max(which(as.logical(a))) - 1
c(numeric(n), tail(a, -n))

Upvotes: 3

Matthew Plourde
Matthew Plourde

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

MrFlick
MrFlick

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

Thomas
Thomas

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

akrun
akrun

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

Related Questions