Is the argument included in the page list? - r

I want to define the operator %in%, whose operation is to return TRUE if the argument on the left is in the list on the right and FALSE otherwise. The task should be implemented without using a loop.
### Creating a simple list
ell <- list( 2, c( 2, 5), list( c( 2, 8)), "xyz")
### Testing of selected elements
2 %in% ell
5 %in% ell
list( c( 2, 8)) %in% ell
list( list( 2, 8)) %in% ell
"xyz" %in% ell
[1] TRUE
[1] FALSE
[1] TRUE
[1] FALSE
[1] TRUE

Like MrFlick said in a comment, do not override built-in operators, it will definitely break something.
Try this one and see if it does what you want. I have named the new operator %IN%, since R is case sensitive.
`%IN%` <- function(x, y){
x %in% unlist(y, recursive = FALSE)
}
2 %IN% ell
#[1] TRUE
5 %IN% ell
#[1] TRUE
list( c( 2, 8)) %IN% ell
#[1] TRUE
list( list( 2, 8)) %IN% ell
#[1] FALSE
"xyz" %IN% ell
#[1] TRUE

Related

R: how to check if a vector is found in another vector of different length without using %in%

vector_1 = c(4,3,5,1,2)
vector_2 = c(3,1)
output:
[1] FALSE TRUE FALSE TRUE FALSE
how do I get the output just by using basic operators/loops without using the operator %in% or any functions in R?
See match.fun(`%in%`)
match(vector_1,vector_2, nomatch = 0) > 0
Without "functions" is a bit vague, since virtually anything in R is a function. Probably that's an assignment and a for loop is wanted.
res <- logical(length(vector_1))
for (i in seq_along(vector_1)) {
for (j in seq_along(vector_2)) {
if (vector_1[i] == vector_2[j])
res[i] <- TRUE
}
}
res
# [1] FALSE TRUE FALSE TRUE FALSE
However, that's not very R-ish where you rather want to do something like
apply(outer(vector_1, vector_2, `==`), 1, \(x) x[which.max(x)])
# [1] FALSE TRUE FALSE TRUE FALSE
Data:
vector_1 <- c(4, 3, 5, 1, 2)
vector_2 <- c(3, 1)
One way with sapply() -
sapply(vector_1, function(x) any(x == vector_2))
[1] FALSE TRUE FALSE TRUE FALSE

How to check if an R object has a certain attribute?

How can I check if an R object has a certain attribute?
For example, I would like to check if a vector has a "labels" attribute. How can I do this? Exists already a function that does that?
my_vector <- c(1, 2, 3)
my_vector_labelled <- `attr<-`(my_vector, "labels", c(a = 1, b = 2, c = 3))
let's assume there is a function named has_attribute(x, attr). The the expected result would be:
> has_attribute(my_vector, "labels")
FALSE
> has_attribute(my_vector_labelled, "labels")
TRUE
Two ways:
%in% names(attributes(..):
"labels" %in% names(attributes(my_vector))
# [1] FALSE
"labels" %in% names(attributes(my_vector_labelled))
# [1] TRUE
is.null(attr(..,"")):
is.null(attr(my_vector, "labels"))
# [1] TRUE # NOT present
is.null(attr(my_vector_labelled, "labels"))
# [1] FALSE # present
(Perhaps !is.null(attr(..)) is preferred?)
There is a function available in package
> library(BBmisc)
> hasAttributes(my_vector_labelled, "labels")
[1] TRUE
> hasAttributes(my_vector, "labels")
[1] FALSE
Use attributes.
my_vector <- c(1, 2, 3)
my_vector_labelled <- `attr<-`(my_vector, "labels", c(a = 1, b = 2, c = 3))
attributes(my_vector)
#> NULL
names(attributes(my_vector_labelled))
#> [1] "labels"
has_attribute <- function(x, which){
which %in% names(attributes(x))
}
has_attribute(my_vector_labelled, "labels")
#> [1] TRUE
Created on 2022-03-31 by the reprex package (v2.0.1)

Is there a better way to check if all elements in a list are named?

I want to check if all elements in a list are named. I've came up with this solution, but I wanted to know if there is a more elegant way to check this.
x <- list(a = 1, b = 2)
y <- list(1, b = 2)
z <- list (1, 2)
any(stringr::str_length(methods::allNames(x)) == 0L) # FALSE, all elements are
# named.
any(stringr::str_length(methods::allNames(y)) == 0L) # TRUE, at least one
# element is not named.
# Throw an error here.
any(stringr::str_length(methods::allNames(z)) == 0L) # TRUE, at least one
# element is not named.
# Throw an error here.
I am not sure if the following base R code works for your general cases, but it seems work for the ones in your post.
Define a function f to check the names
f <- function(lst) length(lst) == sum(names(lst) != "",na.rm = TRUE)
and you will see
> f(x)
[1] TRUE
> f(y)
[1] FALSE
> f(z)
[1] FALSE
We can create a function to check if the the names attribute is NULL or (|) there is blank ("") name, negate (!)
f1 <- function(lst1) is.list(lst1) && !(is.null(names(lst1))| '' %in% names(lst1))
-checking
f1(x)
#[1] TRUE
f1(y)
#[1] FALSE
f1(z)
#[1] FALSE
Or with allNames
f2 <- function(lst1) is.list(lst1) && !("" %in% allNames(lst1))
-checking
f2(x)
#[1] TRUE
f2(y)
#[1] FALSE
f2(z)
#[1] FALSE

Implementing operator

I need to implement operator %in%, which gives TRUE if point on the left is in the list on the right and gives FALSE in opposite case. Problem is that i cannot use a loop and any extra packages.
Creating a list
ell <- list( 2, c( 2, 5), list( c( 2, 8)), "test")
Elements in list
2
c(2, 5)
list(c(2, 8))
"test"
Testing elements
2 %in% ell
# TRUE
5 %in% ell
# FALSE
list(c(2, 8)) %in% ell
# TRUE
list(list(2, 8)) %in% ell
# FALSE
"test" %in% ell
# TRUE
%in% is an operator that identifies whether the first argument is the subset of the second one. So the ability you expected cannot be achieved by %in%. Here is another solution to get what you want by sapply(). For example:
any(sapply(ell, identical, list(c( 2, 8))))
# [1] TRUE
any(sapply(ell, identical, list(list( 2, 8))))
# [1] FALSE
You can define a custom operator by yourself to implement the method above. I name it %IN%:
`%IN%` <- function(a, b){
any(sapply(b, identical, a))
}
2 %IN% ell
# [1] TRUE
5 %IN% ell
# [1] FALSE
list(c(2, 8)) %IN% ell
# [1] TRUE
list(list(2, 8)) %IN% ell
# [1] FALSE
"test" %IN% ell
# [1] TRUE

Behavior of identical() in apply in R

This is weird.
apply( matrix(c(1,NA,2,3,NA,NA,2,4),ncol = 2), 1, function(x) identical(x[1], x[2]) )
#[1] FALSE TRUE TRUE FALSE
apply( data.frame(a = c(1,NA,2,3),b = c(NA,NA,2,4)), 1, function(x) identical(x[1], x[2]) )
#[1] FALSE FALSE FALSE FALSE
apply( as.matrix(data.frame(a = c(1,NA,2,3),b = c(NA,NA,2,4))), 1, function(x) identical(x[1], x[2]) )
#[1] FALSE FALSE FALSE FALSE
This is due to the names attribute as indicated below by joran. I can obtain the result I expected by:
apply( data.frame(a = c(1,NA,2,3),b = c(NA,NA,2,4)), 1, function(x) identical(unname(x[1]), unname(x[2])) )
or:
apply( data.frame(a = c(1,NA,2,3),b = c(NA,NA,2,4)), 1, function(x) identical(x[[1]], x[[2]]) )
Is there a more natural way to approach this? It would seem that there should be an option to ignore attributes, like in all.equal().
Probably
mapply(identical, x$a, x$b)
#[1] FALSE TRUE TRUE FALSE
where x is a data frame.
As an aside, using apply with a data frame is almost always a mistake. It will coerce the data frame to a matrix which often leads to unexpected results.

Resources