Test if a vector contains a given element
Asked Answered
K

8

638

How to check if a vector contains a given value?

Kimsey answered 23/7, 2009 at 2:20 Comment(7)
sometimes I ask myself why R just doesn't use the word contains to make it users easierSublingual
consider that "in" is contained in "conta(in)s"; I'd contend that "in" is a considerably concise contender in this contextRedvers
Perhaps with the addition of flanking %-signs that is. The word in is a reserved word in R use in for-loop construction.Genius
@Sublingual 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")).Wooten
Is there a concise way to do it for real valued numbers with a given precision?Ekg
@Ekg - sure, but that's probably a new question.Sthilaire
@Sublingual in also exist in popular languages such as JavaScript, Python and SQL, so not sure what so special about in R in particular- I would even bet R creators took it from one of them.Tannic
K
602

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
Kimsey answered 23/7, 2009 at 2:25 Comment(4)
what about getting all appearances, not just the first one?Remission
Maybe I come a little late. which(v, 'b'). Mind the order of the arguments.Pommard
Your which(v, 'b') gives me an error message: >Error in which(v, 'b') : argument to 'which' is not logicalDiscover
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.Councilwoman
L
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
Lifesaving answered 2/10, 2013 at 12:3 Comment(4)
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'tBoltonia
@Boltonia : Could you give an example of this?Dedifferentiation
@Boltonia is it fixed?Coddle
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.Sideburns
L
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

Litton answered 7/6, 2017 at 12:52 Comment(1)
As already commented here and here, don't use grep() or regular expressions to find exact matches.Kendalkendall
O
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
Outlawry answered 20/8, 2009 at 22:12 Comment(2)
Be aware this behaves differently from %in%: any(1==NA) returns NA, where 1 %in% NA returns FALSE.Imbecilic
@user3603486: any(1==NA, na.rm=TRUE) returns FALSE.Missis
R
37

You can use the %in% operator:

vec <- c(1, 2, 3, 4, 5)
1 %in% vec # true
10 %in% vec # false
Rania answered 23/7, 2009 at 2:25 Comment(0)
E
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))]
Evangelin answered 18/8, 2013 at 1:12 Comment(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 #1169888Hillard
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]Anhanhalt
O
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.

Outherod answered 3/12, 2015 at 1:2 Comment(3)
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).Fuqua
Do not use regex for exact matches. This is dangerous and can have unexpected resultsTannic
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.Imbecilic
B
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)

Baranowski answered 16/7, 2022 at 18:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.