HOWTO · R

How to Find a Row Number in R

Find matching row positions in R data frames and vectors with which() and match().

On this page

Use which() to find every row position that meets a condition, or match() to find the first position for each value you request. For example, which(staff$role == "Senior Dev") returns the position of each matching row in staff. If no row meets the condition, which() returns integer(0). With match(), a missing query returns NA.

These positions are row numbers when the logical test or lookup vector follows the data frame’s row order. For ordinary R data frames, row positions start at 1. If you need the row label instead, compare rownames(data) or look it up with match().

Find Row Numbers with which()

which() takes a logical vector and returns the positions where its values are TRUE. A comparison against a data-frame column creates that logical vector, so the returned positions identify rows in the same order as the data frame. The function returns all matches, making it a good fit for conditions that can select multiple rows.

Run this example:

staff <- data.frame(
  name = c("Ari", "Bea", "Chen", "Devi"),
  role = c("Analyst", "Senior Dev", "Senior Dev", "Manager")
)
which(staff$role == "Senior Dev")

The result contains positions 2 and 3 because both rows have that role. To find rows by a numeric or compound condition, change the logical expression; for example, which(grades$Math > 80) selects every row whose Math value exceeds 80. Keep the data frame’s row order in mind if you later use these positions to subset another object.

For custom row names, compare the labels returned by rownames():

people <- data.frame(name = c("Ari", "Bea", "Chen"))
rownames(people) <- c("north", "central", "south")
which(rownames(people) == "central")

This returns the position of the row whose label is central; the label itself is not the row number. If you already have a vector aligned one-to-one with the rows, which(values == target) works the same way. For a standalone vector, call the result a position; it is a row number only when that vector represents the data frame’s rows.

If the comparison contains missing values, which() does not return their positions. If you need to treat missing values as a condition, handle them explicitly in the logical expression before calling which().

Find a Value’s First Position with match()

Use match(query, table) when you want the first position of a value in a vector, column, or row-name vector. query can contain one value or several; the result has one position per query. Unlike which(), match() returns only the first occurrence for each query. A query absent from table produces NA by default.

For a data-frame column, put the sought value first and the column second:

staff <- data.frame(
  role = c("Analyst", "Senior Dev", "Senior Dev", "Manager")
)
match("Senior Dev", staff$role)

The returned position is 2, the first matching row, even though the value appears again later. The same form works for vectors: match(78, grades) finds the first position of 78. Use match("central", rownames(people)) to get the position for a row label.

Pass multiple requested values as a vector to get a position for each one:

grades <- c(88, 90, 75, 94, 80)
match(c(75, 94, 70), grades)

The result gives the positions for 75 and 94, followed by NA for 70. The positions stay in query order, not table order. If the table contains duplicates, each query still maps to its first occurrence. When a query is absent, check for NA before using the position to subset another object.

Conclusion

Choose which() when a condition may match multiple rows and you need every position; it returns integer(0) when nothing matches. Choose match() when you have one or more values to look up and need the first position for each; it returns NA for an absent value. For either function, positions correspond to data-frame rows only when the searched vector has the same row order. Use rownames() when the row label, rather than its position, is what you need.