You can use match
match(b, sort(unique(b)))
# [1] 1 3 3 2 2 2 1 3 1
As mentioned by Jesper in the comments another option is
as.integer(factor(b))
Gregor mentioned dense_rank
from dplyr
dplyr::dense_rank(b)
and frank
from data.table
data.table::frank(b, ties.method = "dense")
but match
is most efficient given below sample data
set.seed(1)
b <- sample(round(rnorm(3), 2), 100000, replace = TRUE)
benchmark <- microbenchmark(
match = match(b, sort(unique(b))),
factor = as.integer(factor(b)),
dplyr = dplyr::dense_rank(b),
data.table = data.table::frank(b, ties.method = "dense")
)
autoplot(benchmark)

benchmark
#Unit: milliseconds
# expr min lq mean median uq max neval cld
# match 3.860337 3.992396 4.507669 4.408813 4.712448 7.77195 100 a
# factor 98.624234 100.011022 106.285972 103.896008 108.603783 147.02728 100 d
# dplyr 22.824663 23.388366 25.112084 24.062046 25.720228 39.88105 100 c
# data.table 6.370802 6.563733 8.854151 6.773746 7.476541 51.12899 100 b