Marcin
Marcin

Reputation: 98

Modify %in% operator to find an object in a list

I have to modify %in% operator which will find an objects in a list.

I have a list: list1 <- list(c(5,6), 6, list(2, c(5, 6)), "string")

Non-modified %in% operator after testing these values:

c(5,6) %in% list1
6 %in% list1
2 %in% list1
list(2, c(5,6)) %in% list1 

will return:

TRUE
TRUE
FALSE
FALSE

but for list(2, c(5,6)) %in% list1 I need it to return TRUE as it is an element of this list.

I have to implement it without using loops and I got stuck.

Upvotes: 4

Views: 112

Answers (2)

Julius Vainora
Julius Vainora

Reputation: 48221

In case all you want is to detect this element in the list rather than necessarily defining an operator, there is no need for anything fancy; we can simply add another list as to make it clear that it's a single element that we are interested in:

list(list(2, c(5,6))) %in% list1
# [1] TRUE

Update: while this may be intuitive, what exactly is happening isn't so clear. As @BenBolker observed, %in% is based on match, whose description says

Factors, raw vectors and lists are converted to character vectors, and then x and table are coerced to a common type (the later of the two types in R's ordering, logical < integer < numeric < complex < character) before matching.

So, it would seem that list(list(2, c(5,6))) and list1 first get (somehow) converted to character vectors. As we need to maintain the structure and ordering one sensible guess that it directly means

as.character(list(list(2, c(5,6)))) %in% as.character(list1)

where

as.character(list(list(2, c(5,6))))
# [1] "list(2, c(5, 6))"

as.character(list1)
# [1] "c(5, 6)"          "6"                "list(2, c(5, 6))" "string"   

Upvotes: 2

dave-edison
dave-edison

Reputation: 3736

purrr::has_element should give you what you want:

purrr::has_element(list1, c(5,6))
#[1] TRUE
purrr::has_element(list1, 6)
#[1] TRUE
purrr::has_element(list1, 2)
#[1] FALSE
purrr::has_element(list1, list(2, c(5,6)))
#[1] TRUE

You could also write your own infix function that wraps around this function and works like %in%:

`%in2%` <- function(lhs, rhs) purrr::has_element(rhs, lhs)

c(5,6) %in2% list1
#[1] TRUE
6 %in2% list1
#[1] TRUE
2 %in2% list1
#[1] FALSE
list(2, c(5,6)) %in2% list1
#[1] TRUE

Upvotes: 4

Related Questions