R implement group generics Ops() to enable compari

2019-07-12 17:55发布

I am creating an S3 class in R for which I would like to be able to do comparisons like "<", ">", and "==". Rather than implement each of these separately from what I've read about group generics I believe I can do so using Ops() but I haven't found any good examples of how to do this.

Suffice it to say that for myClass I can create an as.integer.myClass() function, and that to compare a and b I could just convert to integer first:

if(as.integer(a) < as.integer(b)) foo

This totally works, but I would so much rather write

if(a < b) foo

I thought this would work, but it doesn't:

Ops.myClass <- function(e1, e2) {
  Ops(as.integer(e1), as.integer(e2))
}
a < b
Error in (function (classes, fdef, mtable)  :
 unable to find an inherited method for function ‘Ops’ for signature ‘"integer", "integer"’ 

Any help? Thanks!

2条回答
叼着烟拽天下
2楼-- · 2019-07-12 18:19

Note that Ops(my, my) fails with the same error -- you're not invoking Ops, but a generic that is a member of the Ops group. So get the generic and invoke it on the transformed types

Ops.my = function(e1, e2) get(.Generic)(as.integer(e1), as.integer(e2))

with

> my1 = structure(1:5, class="my")
> my2 = structure(5:1, class="my")
> my1 > my2
[1] FALSE FALSE FALSE  TRUE  TRUE
> my1 == my2
[1] FALSE FALSE  TRUE FALSE FALSE
查看更多
劳资没心,怎么记你
3楼-- · 2019-07-12 18:28

The general approach I have for this is to use .Generic and switch on the method.

Ops.myClass <- function(e1, e2)
{
  op = .Generic[[1]]
  switch(op,
         `<` = {
           print("called less than function")
           as.integer(e1) < as.integer(e2)
         },
         `>` = {
            print("called greater than function")
            as.integer(e1) > as.integer(e2)
         },
         stop("undefined operation")
  )
}

a <- 1
b <- 3
class(a) <- "myClass"
class(b) <- "myClass"


a > b
[1] "called greater than function"
[1] FALSE
a < b
[1] "called less than function"
[1] TRUE
查看更多
登录 后发表回答