How to Find the Difference Between Two Vectors in R

R's base setdiff() covers most vector-difference needs in one call, but like every set-based approach it drops duplicates and direction matters. Here are the four approaches worth knowing, including the dplyr equivalent for data frames.

Quick answer

setdiff(a, b) returns elements in a not in b, but treats both as sets - duplicates are dropped and direction matters (setdiff(a, b) differs from setdiff(b, a)). To keep duplicates and original order, use a[!a %in% b] instead. For symmetric difference, use union(setdiff(a, b), setdiff(b, a)). For data frames matched by a key column, use dplyr's anti_join(df_a, df_b, by = 'id').

Need the same thing in another language?

See the full reference for Python, JavaScript, SQL, Java, and more.

See every language →

setdiff(): the standard base R function

a <- c("apple", "banana", "cherry", "banana")
b <- c("banana", "date")

a_only <- setdiff(a, b)
print(a_only)  # "apple"  "cherry" - duplicate "banana" dropped, order not guaranteed

setdiff(a, b) treats both vectors as sets: any duplicate values in a collapse to one occurrence in the output, and the direction matters - setdiff(b, a) would give you a completely different result (just "date" here).

a[!a %in% b]: preserving duplicates and order

a <- c("apple", "banana", "cherry", "banana")
b <- c("banana", "date")

a_only <- a[!a %in% b]
print(a_only)  # "apple"  "cherry" - both "banana"s filtered, "apple" and "cherry" keep their position

%in% checks each element of a against the whole of b and returns a logical vector, which ! then negates to keep only non-matches. Unlike setdiff(), this is a filter rather than a set operation - it preserves a's original order and any duplicate values that aren't themselves in b.

Symmetric difference: items unique to either vector

a <- c("apple", "banana", "cherry")
b <- c("banana", "date")

sym_diff <- union(setdiff(a, b), setdiff(b, a))
print(sym_diff)  # "apple"   "cherry"  "date"

R has no single function for symmetric difference, but combining both one-way setdiff() calls with union() gets there in one line - everything unique to a plus everything unique to b.

dplyr anti_join(): the data frame equivalent

library(dplyr)

df_a <- data.frame(id = c(1, 2, 3), name = c("a", "b", "c"))
df_b <- data.frame(id = c(2, 3, 4), name = c("b", "c", "d"))

only_in_a <- anti_join(df_a, df_b, by = "id")
print(only_in_a)  # row with id = 1

When you're comparing data frames rather than plain vectors and want to match rows by a key column, anti_join() is the tidyverse equivalent of a vector difference - it returns rows from df_a whose id doesn't appear in df_b, without requiring the two frames to have identical columns the way setdiff() on whole data frames would.

NA handling: the pitfall that catches people out

NA in R is never equal to another NA under standard equality rules, but %in% and setdiff() specifically treat NA as matching NA - which is the opposite of what == would do. If your vectors contain NA values and you need standard IEEE-style behavior instead, filter them out explicitly with na.omit() before comparing.

Just need the answer, not the code? Paste both lists.

Open Compare 2 Lists →

Frequently Asked Questions

What is setdiff() in R and does direction matter?
setdiff(a, b) returns elements in a that are not in b. Direction matters and is not commutative: setdiff(a, b) and setdiff(b, a) give different results unless the two vectors happen to be identical.
Does setdiff() preserve duplicates?
No. setdiff() treats both vectors as sets, so duplicate values within a collapse to a single occurrence in the result - even if that value doesn't appear in b at all. If you need duplicates preserved, use a[!a %in% b] instead.
What is the difference between setdiff(a, b) and a[!a %in% b]?
setdiff(a, b) deduplicates the result and doesn't guarantee the original order. a[!a %in% b] keeps every element of a not found in b, including duplicates, in a's original order - it's a filter, not a set operation.
How do I get the symmetric difference between two vectors in R?
There's no single built-in function, but it's one line: union(setdiff(a, b), setdiff(b, a)) combines everything unique to a with everything unique to b.
Why do factors behave differently from character vectors in setdiff()?
Comparing a factor to a character vector (or two factors with different level sets) can produce unexpected results, since factors compare by their underlying integer level codes in some contexts rather than their displayed labels. Convert factors to character with as.character() before comparing to avoid this entirely.

Share this tool

Featured on ToolDirs
© 2026 ListDiff

Free online list and text processing tools.