match()
match(x, table, nomatch = NA_integer_, incomparables = FALSE) match() returns the position of the first match between elements of x in table.
Syntax
match(x, table, nomatch = NA_integer_, incomparables = FALSE)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
x | vector | , | The values to look up |
table | vector | , | The values to match against |
nomatch | integer | NA_integer_ | Value to return when no match is found |
incomparables | vector | FALSE | Values in x that cannot be matched |
Examples
Basic usage
x <- c("a", "b", "c", "d")
table <- c("b", "c", "e")
match(x, table)
# [1] NA 1 2 NA
The basic call shows match() comparing each element of x against table and returning the position where it first appears. Elements not found in table receive NA — the default for nomatch. This is the foundation for all lookup-based operations with match().
Using nomatch parameter
match(c("apple", "cherry"), c("apple", "banana"), nomatch = 0)
# [1] 1 0
Setting nomatch = 0 replaces NA with a numeric sentinel, which avoids NA propagation in downstream arithmetic. This is especially useful when match() output feeds directly into computations where NA would cascade. In practice, a sentinel can also be a negative number or any value that is safely distinguishable from valid match positions.
Finding unique or duplicate values
new_values <- c("apple", "banana", "cherry", "apple")
seen <- c("apple", "banana")
# Get indices of matches
idx <- match(new_values, seen)
idx
# [1] 1 2 NA 1
This example demonstrates detecting which new values have been seen before — the NA at position 3 tells you “cherry” is new, while the 1 at position 4 confirms the second “apple” maps to the first position in seen. This pattern underlies deduplication and incremental processing workflows where you maintain a running set of known identifiers.
Practical data cleaning
df <- data.frame(
category = c("A", "B", "C", "D", "A"),
value = 1:5
)
allowed <- c("A", "B")
idx <- match(df$category, allowed)
idx
# [1] 1 2 NA NA 1
Common patterns
Deduplication: Identify which values in one vector appear in another. By combining match() with is.na(), you can separate seen values from new ones — a pattern that appears in data validation, incremental file processing, and any workflow where you maintain a master list and need to check incoming values against it.
existing_ids <- c(101, 102, 103)
new_ids <- c(101, 104, 105, 103)
# Which new IDs already exist?
!is.na(match(existing_ids, new_ids))
# [1] TRUE FALSE FALSE
# Get only the new IDs
setdiff(new_ids, existing_ids)
# [1] 104 105
match() in practice
match(x, table) returns the position of the first match for each element of x in table. When an element of x is not found in table, the result is NA. This makes match() a lookup function: table[match(x, names)] is equivalent to a dictionary lookup, returning the value at the position where x matches the key.
%in% is built on match(): x %in% table is equivalent to !is.na(match(x, table)). For membership testing alone, %in% is more readable. Use match() when you need the actual position, not just whether a match exists.
A common pattern: aligning two vectors by a shared key. match(df1$id, df2$id) returns the row in df2 that corresponds to each row in df1. df2[match(df1$id, df2$id), ] reorders df2 to align with df1, a manual join. For this operation at scale, merge() or dplyr::left_join() is more efficient and handles duplicates and NA more explicitly.
match() finds the first match only. For finding all matches, use which(table == x[i]) in a loop or lapply(x, function(v) which(table == v)). For large tables, converting to a hash via setNames(seq_along(table), table) and using named list access is faster than repeated match() calls.
match() returns the position of each element of x in table, or NA if not found. It returns only the first match for each element. x %in% table is the logical version, it returns TRUE/FALSE rather than positions. For joining data frames, match() is the engine behind merge: df1[match(df2$id, df1$id), ] is a manual left-join. When table has unique values, match() is faster than which() for repeated lookups.
match() returns the position of each element of x in table, returning NA where no match is found. For checking membership without needing positions, x %in% table is cleaner, it returns a logical vector and is implemented as !is.na(match(x, table)).
match() returns the first match when table contains duplicates. If you need all matching positions, which(table == value) gives every position. For vectorized lookup, match() is efficient because it builds a hash table internally — it is faster than a loop for large x or table.
A common pattern is using match() to reorder or subset: df[match(key_vector, df$id), ] returns rows of df in the order specified by key_vector, with NA rows for unmatched keys. This is the basis of manual left-join operations in base R.
pmatch() allows partial string matching. charmatch() is similar but stricter. Both are useful for matching abbreviated user input against a table of valid values in function argument handling.