638

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
    – greg121
    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.
    – IRTFM
    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?
    – mlt
    Commented Nov 16, 2018 at 19:45

8 Answers 8

603
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
4
  • what about getting all appearances, not just the first one? Commented Mar 15, 2018 at 0:54
  • 1
    Maybe I come a little late. which(v, 'b'). Mind the order of the arguments. Commented Dec 19, 2018 at 19:40
  • Your which(v, 'b') gives me an error message: >Error in which(v, 'b') : argument to 'which' is not logical Commented Aug 17, 2019 at 10:08
  • 1
    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.
    – khtad
    Commented Jun 26, 2020 at 21:33
207

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
  • 8
    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
    Commented Dec 28, 2014 at 6:21
  • @pomber : Could you give an example of this?
    – discipulus
    Commented Jun 27, 2017 at 6:24
  • @pomber is it fixed?
    – vasili111
    Commented Sep 21, 2019 at 23:28
  • 9
    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. Commented Jan 3, 2020 at 16:36
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
  • 8
    As already commented here and here, don't use grep() or regular expressions to find exact matches.
    – Uwe
    Commented Jun 13, 2017 at 10:04
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
  • 11
    Be aware this behaves differently from %in%: any(1==NA) returns NA, where 1 %in% NA returns FALSE.
    – user3603486
    Commented Mar 23, 2017 at 1:34
  • @user3603486: any(1==NA, na.rm=TRUE) returns FALSE.
    – AkselA
    Commented Apr 23, 2019 at 20:57
37

You can use the %in% operator:

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

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
  • 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/… Commented Feb 7, 2015 at 16:27
  • 2
    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]
    – Houshalter
    Commented Feb 20, 2017 at 23:11
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
  • 12
    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). Commented Jan 7, 2016 at 7:45
  • 12
    Do not use regex for exact matches. This is dangerous and can have unexpected results Commented Sep 10, 2016 at 17:54
  • 10
    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.
    – user3603486
    Commented Mar 23, 2017 at 1:31
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)

Not the answer you're looking for? Browse other questions tagged or ask your own question.