Overriding% to% for matrices

I like working with matrix elements in R with operators like == and | :

 (m <- matrix(1:4, nrow=2)) # [,1] [,2] # [1,] 1 3 # [2,] 2 4 m == 2 | m == 3 # [,1] [,2] # [1,] FALSE TRUE # [2,] TRUE FALSE 

Unfortunately, %in% does not have the same nice behavior and returns a vector instead of a matrix:

 m %in% c(2, 3) # [1] FALSE TRUE TRUE FALSE 

Noting that %in% is defined as function(x, table) match(x, table, nomatch = 0L) > 0L , I decided that I could override match to get the desired behavior:

 match <- function(x, table, nomatch = NA_integer_, incomparables = NULL) { m <- base:::match(x, table, nomatch, incomparables) if (is.matrix(x)) matrix(m, nrow(x)) else m } 

While this works, if I explicitly call match , I still do not get the desired result when running m %in% c(2, 3) :

 match(m, c(2, 3), nomatch=0L) > 0L # [,1] [,2] # [1,] FALSE TRUE # [2,] TRUE FALSE m %in% c(2, 3) # [1] FALSE TRUE TRUE FALSE 

Why now %in% does not return a matrix?

+5
source share
2 answers

Thanks to @joran for pointing me to this excellent article that explained to me why %in% did not use my new match function. Here is my understanding of what is going on:

The user- match function is stored in the global environment, and the original match function is stored in namespace:base :

 environment(match) # <environment: R_GlobalEnv> environment(base::match) # <environment: namespace:base> 

Now consider what happens when I call m %in% c(2, 3) :

  • Executes the function %in% , which is defined as function(x, table) match(x, table, nomatch = 0L) > 0L .
  • The function must find the match function, so it first searches in its local environment, which was created as part of the function call. match is not defined there.
  • The next place to look for match is the function environment. We can understand what it is:

 environment(`%in%`) # <environment: namespace:base> 
  1. Since the original version of match (and not the user version) is defined in namespace:base , this is the version of the function being called.

To work with my matrix version of %in% , the easiest approach is to follow @Molx's recommendations and override %in% to be stored in a global environment (note that there is still an identical version of the function in namespace:base ):

 `%in%` <- function(x, table) match(x, table, nomatch = 0L) > 0L environment(`%in%`) # <environment: R_GlobalEnv> 

Now m %in% c(2, 3) will look for the match function first in its local functional environment, and then in the environment ( R_GlobalEnv ), finding our custom version of the match function:

 m %in% c(2, 3) # [,1] [,2] # [1,] FALSE TRUE # [2,] TRUE FALSE 

Another way we could use %in% to use the custom match function would be to change the environment of base::"%in%" in the global environment:

 rm(`%in%`) # Remove user-defined %in% environment(`%in%`) <- .GlobalEnv # Can be reversed with environment(`%in%`) <- asNamespace("base") m %in% c(2, 3) # [,1] [,2] # [1,] FALSE TRUE # [2,] TRUE FALSE 

As @Molx commentators have already pointed out, the most sensible thing is to avoid all this headache by calling my new function something like %inm% .

+3
source

I'm not sure why your attempt did not work, but I believe that %in% will use base:::match regardless of your overridden match . But why not override %in% yourself?

 `%in%` <- function(x, table) { m <- base::match(x, table, nomatch = 0L) > 0L if (is.matrix(x)) matrix(m, nrow(x)) else m } m <- matrix(1:4, nrow=2) m %in% c(2, 3) # [,1] [,2] # [1,] FALSE TRUE # [2,] TRUE FALSE 

As stated in the comments and usually from a best practice point of view, it would be safer to use a different name, such as %inm% or %min% .

+3
source

All Articles