rguides

position

R has no single function called position(). Instead, several related functions handle positional indexing: which.max(), which.min(), rank(), and order(). This article covers them together, since they’re often used in combination to answer “where is the max?”, “what’s the rank order?”, and “what indices would sort this?“

which.max — Position of the Maximum

which.max returns the index of the first maximum value in a vector:

which.max(c(1, 3, 2, 3, 0))
# [1] 2

With ties, it returns the position of the first occurrence:

which.max(c(1, 3, 3, 3, 2))
# [1] 2  (first 3 is at position 2)

which.min is the equivalent for the minimum:

which.min(c(5, 1, 3))
# [1] 2

Both functions ignore NA and NaN values by default:

which.max(c(1, NA, 3, 2))
# [1] 3

To handle NAs explicitly, prefilter:

x <- c(1, NA, 3, 2)
which.max(x[!is.na(x)])
# [1] 3
which.max(na.omit(x))
# [1] 3

rank — Rank Values in a Vector

rank assigns ranks to values. The default tie method is "average":

rank(c(3, 1, 2))
# [1] 3 1 2

With ties, "average" assigns the mean rank:

rank(c(1, 2, 2, 3))
# [1] 1.0 2.5 2.5 4.0

Other tie methods handle ties differently:

rank(c(1, 2, 2, 3), ties.method = "first")
# [1] 1 2 3 4

rank(c(1, 2, 2, 3), ties.method = "min")
# [1] 1 2 2 4

rank(c(1, 2, 2, 3), ties.method = "max")
# [1] 1 3 3 4

na.last controls where NA values land:

rank(c(1, NA, 2), na.last = TRUE)
# [1] 1 NA 2  -- NA gets a rank

rank(c(1, NA, 2), na.last = FALSE)
# [1] NA  1  2  -- NA comes first

rank(c(1, NA, 2), na.last = NA)
# [1] 1 2  -- NA is removed

order — Indices for Sorting

order returns indices that would sort a vector:

order(c(3, 1, 2))
# [1] 2 3 1
# element at position 2 (value 1) comes first
# element at position 3 (value 2) comes second
# element at position 1 (value 3) comes third

Use these indices to reorder another vector:

x <- c("c", "a", "b")
x[order(c(3, 1, 2))]
# [1] "a" "b" "c"

For descending order:

order(c(3, 1, 2), decreasing = TRUE)
# [1] 1 3 2

Sort data frames by passing column arguments:

df <- data.frame(name = c("bob", "alice", "carol"), score = c(85, 92, 78))
df[order(df$score), ]
#     name score
# 3  carol    78
# 1    bob    85
# 2  alice    92

Getting the Position of a Specific Value

To find positions matching a condition, use which():

x <- c(10, 20, 30, 40, 50)
which(x == 30)
# [1] 3

which(x > 25)
# [1] 3 4 5

For the first occurrence of a match, use match():

match(30, c(10, 20, 30, 40, 50))
# [1] 3

# Check existence of values:
30 %in% c(10, 20, 30, 40, 50)
# [1] TRUE

xtfrm — Auxiliary Sorting

xtfrm() produces a numeric vector that sorts in the same order as the input. It’s used internally by sort() and order() for non-numeric objects:

xtfrm(c("b", "a", "c"))
# [1] 2 1 3  (a=1, b=2, c=3)

# Useful for custom orderings:
xtfrm(factor(c("low", "high", "medium"),
            levels = c("low", "medium", "high")))
# [1] 1 3 2

Relationship Between These Functions

FunctionReturnsExample inputExample output
which.max(x)index of first maxc(3,1,2)1
which.min(x)index of first minc(3,1,2)2
rank(x)rank of each elementc(3,1,2)3, 1, 2
order(x)indices for sortingc(3,1,2)2, 3, 1
match(val, x)index of first match30, c(10,20,30)3

Common Patterns

Find the Maximum Value (Not Just Its Position)

x <- c(3, 1, 4, 1, 5, 9)
x[which.max(x)]
# [1] 9

Get Top N Indices

order(x, decreasing = TRUE)[1:3]
# indices of the 3 largest values

Rank in Descending Order

rank(-x)

Common Pitfalls

Forgetting That which.max Returns an Index, Not the Value

which.max(x)      # index
x[which.max(x)]   # the actual value

Ties Give Unexpected Results With which.max

which.max(c(1, 2, 2, 2))
# [1] 2  -- only first occurrence

# Get ALL positions of max:
which(x == max(x))
# [1] 2 3 4

See Also