I have a string of numbers, and a list:
a <- c(1,2,3)
b <- list( x<-c(1:5),y<-c(1:10),z<-c(10:20))
What I want to do is to test whether each number is in each element of the list -- whether 1 is in x, 2 is in y, 3 is in z. And then give 1/0 to a new variable.
My code:
d <- ifelse(a %in% sapply(b,function(x) unlist(x)),1,0)
However the result:
> d
[1] 0 0 0
And desirable result should be:
[1] 1 1 0
How can I do this? Thank you
You're looping over two matching sets of data, which suggests Map/mapply
:
mapply(`%in%`, a, b)
#[1] TRUE TRUE FALSE
as.integer(mapply(`%in%`, a, b))
#[1] 1 1 0
The purrr
package has a number of variations on the *apply
family and helper functions useful for working with lists. In this case, it would look like
library(purrr)
map2_int(a, b, ~.x %in% .y) # shorthand for map2_int(a, b, function(x, y){x %in% y})
## [1] 1 1 0
or
map2_int(a, b, `%in%`)
## [1] 1 1 0
where
map
part is the name of a set of functions that apply a function to the elements of a list,2
part is a version that takes two lists as input and iterates over them in parallel, and_int
part is a version that simplifies the result to an integer vector.It is worth noting that is.element
is the equivalent of %in%
, so you can avoid typing some quotation marks. If you like purrr
, you can get the right answer with
map2_int(a,b, is.element)
[1] 1 1 0
The best way to mimic a for loop
with apply
functions is to actually define an iterator.
sapply(1:length(b), function(i) a[i] %in% b[[i]])
This will return booleans
[1] TRUE TRUE FALSE
convert to int with as.integer()
I feel like this is more intuitive than mapply
, and with a self-defined function call, you can tweak around with it, say making a if
statement searching for NA
lists.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With