642

How to check if a vector contains a given value?

7
  • 48
    sometimes I ask myself why R just doesn't use the word contains to make it users easier Commented Mar 4, 2013 at 17:28
  • 23
    consider that "in" is contained in "conta(in)s"; I'd contend that "in" is a considerably concise contender in this context Commented Mar 11, 2016 at 16:34
  • 1
    Perhaps with the addition of flanking %-signs that is. The word in is a reserved word in R use in for-loop construction. Commented Jul 9, 2016 at 0:44
  • @greg121 dplyr already has a contains function, but it's used for a different purpose: to select a column in a data frame. For example select(iris, contains("etal")). Commented Mar 14, 2018 at 9:59
  • Is there a concise way to do it for real valued numbers with a given precision? Commented Nov 16, 2018 at 19:45

8 Answers 8

607
Answer recommended by R Language Collective

Both the match() (returns the first appearance) and %in% (returns a Boolean) functions are designed for this.

v <- c('a','b','c','e') 'b' %in% v ## returns TRUE match('b',v) ## returns the first location of 'b', in this case: 2 
Sign up to request clarification or add additional context in comments.

5 Comments

what about getting all appearances, not just the first one?
Maybe I come a little late. which(v, 'b'). Mind the order of the arguments.
Your which(v, 'b') gives me an error message: >Error in which(v, 'b') : argument to 'which' is not logical
The syntax is which(v == b) or any other logical operator. In this case, the return from this would be 2. If v were c("b", "b", "c", "b", "d"), the return to which(v == b) would be 1, 2, 4.
Note that there are drop-in-replacements fmatch and %fin% in the fastmatch package (see cran.r-project.org/web/packages/fastmatch/index.html). These are much faster for large vectors (thousands of elements and more).
209

is.element() makes for more readable code, and is identical to %in%

v <- c('a','b','c','e') is.element('b', v) 'b' %in% v ## both return TRUE is.element('f', v) 'f' %in% v ## both return FALSE subv <- c('a', 'f') subv %in% v ## returns a vector TRUE FALSE is.element(subv, v) ## returns a vector TRUE FALSE 

4 Comments

I know the documentation says is.element(x, y) is identical to x %in% y. But, I dont know why, is.elements works when mixing integers and numerics and %in% doesn't
@pomber : Could you give an example of this?
@pomber is it fixed?
The superior readability is.element() vs %in% is subjective. A case can be made that an infix operator is more readable because it eliminates ambiguity in the order of arguments. apple in fruit makes sense, fruit in apple does not. is.element(apple, fruit) or is.element(fruit, apple) could both be right depending on implementation of the is.element function.
121

I will group the options based on output. Assume the following vector for all the examples.

v <- c('z', 'a','b','a','e') 

For checking presence:

%in%

> 'a' %in% v [1] TRUE 

any()

> any('a'==v) [1] TRUE 

is.element()

> is.element('a', v) [1] TRUE 

For finding first occurance:

match()

> match('a', v) [1] 2 

For finding all occurances as vector of indices:

which()

> which('a' == v) [1] 2 4 

For finding all occurances as logical vector:

==

> 'a' == v [1] FALSE TRUE FALSE TRUE FALSE 

Edit: Removing grep() and grepl() from the list for reason mentioned in comments

1 Comment

As already commented here and here, don't use grep() or regular expressions to find exact matches.
71

The any() function makes for readable code

> w <- c(1,2,3) > any(w==1) [1] TRUE > v <- c('a','b','c') > any(v=='b') [1] TRUE > any(v=='f') [1] FALSE 

2 Comments

Be aware this behaves differently from %in%: any(1==NA) returns NA, where 1 %in% NA returns FALSE.
@user3603486: any(1==NA, na.rm=TRUE) returns FALSE.
37

You can use the %in% operator:

vec <- c(1, 2, 3, 4, 5) 1 %in% vec # true 10 %in% vec # false 

Comments

21

Also to find the position of the element "which" can be used as

pop <- c(3, 4, 5, 7, 13) which(pop==13) 

and to find the elements which are not contained in the target vector, one may do this:

pop <- c(1, 2, 4, 6, 10) Tset <- c(2, 10, 7) # Target set pop[which(!(pop%in%Tset))] 

2 Comments

which is actually preferable sometimes for it gives you all the matching positions (as an array), unlike match. Although this was perhaps not what the OP asked for, unlike stackoverflow.com/questions/1169388/…
Why bother with which if you just want to find the elements not in Tset? You can just index pop directly; pop[!pop%in%Tset]
13

I really like grep() and grepl() for this purpose.

grep() returns a vector of integers, which indicate where matches are.

yo <- c("a", "a", "b", "b", "c", "c") grep("b", yo) [1] 3 4 

grepl() returns a logical vector, with "TRUE" at the location of matches.

yo <- c("a", "a", "b", "b", "c", "c") grepl("b", yo) [1] FALSE FALSE TRUE TRUE FALSE FALSE 

These functions are case-sensitive.

3 Comments

By default, grep takes a regular expression as its first element, so to do an exact match for "b", either use^e$ or add , fixed=TRUE).
Do not use regex for exact matches. This is dangerous and can have unexpected results
Yeah, this is a terrible, no good, very bad idea - inefficient and guaranteed to break. E.g. myvar <- 'blah'; grepl('b', myvar, fixed=TRUE) will return TRUE even though 'b' is not in myvar.
1

Another option to check if a element exists in a vector is by using the %in{}% syntax from the inops package like this:

library(inops) #> #> Attaching package: 'inops' #> The following object is masked from 'package:base': #> #> <<- v <- c('a','b','c','e') v %in{}% c("b") #> [1] FALSE TRUE FALSE FALSE 

Created on 2022-07-16 by the reprex package (v2.0.1)

1 Comment

This would be a much better answer if there was some explanation of if/how/why this is different from the base v %in% b

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.