Find the indices of last occurrence of the unique elements in a vector
You could try rle
if the vector
is already ordered. Extract the lengths ($lengths)
and then cumsum
. As I mentioned earlier, this will not work if it is not ordered (again it depends on what you really wanted). Basically rle
works by checking the number of consecutive elements that are similar on a stretch. It will give the lengths
and corresponding values
in a list.
cumsum(rle(v1)$lengths)
#[1] 28 37 42 46 50
Another option is to group the sequence by the vector and get the max
value for each group
. I would imagine this to be slow.
unname(cumsum(tapply(seq_along(v1),v1, FUN=which.max)))
#[1] 28 37 42 46 50
Or just check whether the previous value is the same as the current value and then insert TRUE
as the last element, and get the index of TRUE
with which
which(c(v1[-1]!=v1[-length(v1)],TRUE))
#[1] 28 37 42 46 50
Or use match
c(match(unique(v1),v1)-1, length(v1))[-1]
#[1] 28 37 42 46 50
Or use findInterval
findInterval(unique(v1), v1)
#[1] 28 37 42 46 50
Update
For the new vector v2
max.col(t(sapply(unique(v2), `==`, v2)),'last')
#[1] 41 46 45 44 50 27
Or a function using findInterval
after ordering
the unordered vector
f1 <- function(v){
v1 <- setNames(v, seq_along(v))
ind <- order(v1)
as.numeric(names(v1[ind][findInterval(unique(v1), v1[ind])]))
}
f1(v2)
#[1] 41 46 45 44 50 27
Using the example (z
) from @Marat talipov's post,
f1(z)
#[1] 4 5 3
NOTE: I get the result in the order in which the unique elements first appeared in z
. i.e. 1
, followed by 3
, 2
. If it needs to be ordered again based on the values, it can be done using order
(as mentioned by @Marat Talipov). However, it is not clear what the OP really wanted in such situations.
data
v1 <- c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3,
3, 4, 4, 4, 4, 5, 5, 5, 5)
v2 <- c(1, 2, 1, 2, 1, 1, 1, 3, 1, 2, 2, 3, 3, 3, 1, 1, 1, 4, 1, 1,
1, 4, 1, 5, 5, 6, 6, 2, 3, 3, 4, 4, 2, 2, 2, 2, 2, 3, 3, 3, 1,
4, 4, 4, 3, 2, 5, 5, 5, 5)
z <- c(1, 3, 2, 1, 3)
Another approach that works even if the data are not ordered:
length(v1)-match(unique(v1),rev(v1))+1
tapply(seq_along(v), v, max)
# 1 2 3 4 5 6
# 41 46 45 44 50 27
Also could try
which(c(diff(tmp), TRUE) == 1)
# [1] 28 37 42 46 50
Or similarly
which(!!c(diff(tmp), TRUE))