kjo - 1 year ago 77
R Question

# Equivalent of Mathematica's Which

Mathematica's

function is a generalized
`If`
:

`Which[test_1, value_1, test_2, value_2, …]`

evaluates each of the
`test_i`
in turn, returning the value of the
`value_i`
corresponding to the first one that yields
`True`
.

It's nothing more than a handy way to get rid of superfluous syntax from long sequences of nested simple if-else tests.

Does R have an equivalent function?

BTW, I know that I can always do something like

``````if (test_1) value_1 else if (test_2) value_2 else ... value_n else default
``````

or, equivalently,

``````if (test_1) value_1 else
if (test_2) value_2 else
...
if (test_n) value_n else
default
``````

...but, as I already alluded to, when compared to
`Which`
, nested
`if-else`
statements bring in a lot of superfluous syntax.

Also, I'm aware of

``````ifelse(t_1, v_1, ifelse(t_2, v_2, ..., ifelse(t_n, v_n, default)...))
``````

...but the results are sensitive to the shape of the tests, so it is not strictly equivalent to nested
`if-else`
statements.

Lastly, R's
`switch`
statement is similar to what I'm looking for, in that it encapsulates a dispatch over a sequence of tests, but it's not quite the same thing. In

``````switch(expr,
case_1 = value_1,
case_2 = value_2,
...
case_n = value_n,
default)
``````

...the tests are all equality comparisons of
`expr`
against the
`case_i`
, whereas in
`Which`
, etc., the tests are arbitrary boolean expressions.

You can write your own function which can be used as such a control structure. The followed is based on the fact that `match.call` supports lazy evaluation. (See this accepted answer):

``````which.val <- function(...){
clauses <- match.call(expand.dots = FALSE)\$`...`
n <- length(clauses)
for(i in seq(1,n,2)){
condition = eval(clauses[[i]])
if(condition) return(clauses[[i+1]])
}
}
``````

For testing purposes:

``````test <- function(a,b){
print(b)
a == b
}
``````

The side effect can be used to see what is actually evaluated.

For example:

``````> x <- 3
> which.val(test(x,1),10,test(x,2),20,test(x,3),30,test(x,4),40)
[1] 1
[1] 2
[1] 3
[1] 30
``````

Note how `test(x,4)` is never evaluated.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download