3

Is it possible to supply logical (or arithmetic) operators as arguments to R functions. Check this SO question that share the theme.

f1 <- function(a, b) a>b

Then

> f1(1,2)
[1] FALSE

How can I implement an operator that allows me to for instance change the function test, e.g.

f2 <- function(a, b, operator = c('<', '>', '==')) { ... }

Then I would like

> f2(1, 2, '<')
[1] TRUE
user3375672
  • 3,728
  • 9
  • 41
  • 70
  • Possible duplicate of [Subtraction method as variable](https://stackoverflow.com/questions/36699777/subtraction-method-as-variable) – pogibas Sep 08 '17 at 11:58

3 Answers3

7

In R, all operators are functions. So, you only need to get the operator function and call it.

f2 <- function(a, b, operator) getFunction(operator)(a, b)
f2(1, 2, '<')
#[1] TRUE
Roland
  • 127,288
  • 10
  • 191
  • 288
  • 1
    Ah did not knew of `getFunction`. It seems a little more concise than the eval(parse()) approach. And more safe perhaps ? – user3375672 Sep 08 '17 at 12:01
  • 1
    @user3375672 "If the answer is `parse()` you should usually rethink the question." [(fortune 106)](https://cran.r-project.org/web/packages/fortunes/vignettes/fortunes.pdf) – Roland Sep 08 '17 at 12:03
  • 1
    see also [this](https://stackoverflow.com/questions/13649979/what-specifically-are-the-dangers-of-evalparse) – Roland Sep 08 '17 at 12:03
3

Here's another option:

foo <- function(a, b, operator) {
   f <- match.fun(match.arg(operator, choices = c('<', '>', '=='))) 
   f(a,b) 
}

foo(1,2, ">")
#[1] FALSE
foo(1,2, "==")
#[1] FALSE
foo(1,2, "+")
# Show Traceback
# 
# Rerun with Debug
# Error in match.arg(operator, choices = c("<", ">", "==")) : 
#  'arg' should be one of “<”, “>”, “==” 

Using match.arg allows you to restrict it to certain functions. match.fun then gets the actual function.

In case you don't need the restriction to certain inputs, you can skip the match.arg and just use match.fun.

talat
  • 68,970
  • 21
  • 126
  • 157
2

One way to do this is to use eval(parse(...)) methodology, i.e.

f1 <- function(a, b, op){
  eval(parse(text = paste0(a, op, b)))
}

f1(1, 2, '<')
#[1] TRUE
f1(3, 3, '==')
#[1] TRUE
f1(3, 4, '==')
#[1] FALSE
Sotos
  • 51,121
  • 6
  • 32
  • 66