[R] Do NOT use ifelse() if you can use if(.) else . [was "Checking .."]

Martin Maechler maechler at stat.math.ethz.ch
Tue Dec 23 10:05:47 CET 2014


>>>>> Steven Yen <syen04 at gmail.com>
>>>>>     on Sun, 14 Dec 2014 09:30:56 -0500 writes:
>>>>> Steven Yen <syen04 at gmail.com>
>>>>>     on Sun, 14 Dec 2014 09:30:56 -0500 writes:

    > Thanks. This worked!! :)
    > Fisher <- ifelse(!("Fisher" %in% names(obj$spec)), FALSE, obj$spec$Fisher)

"worked",  yes.

But please --- for the mailing list archives ---
do use better code.

Unfortunately, ifelse() is used and has been advertized much too
often in cases where it is very sub-optimal efficiency wise. 
ifelse(Cond, A, B)  should only be used  when the condition
'Cond', a logical vector can be (and typically is) of length > 1
{and even then, it maybe a nice short cut, but often still suboptimal
 efficiency wise ... but let's not get there}

In cases like this one when the condition 'Cond' is a
simple TRUE or FALSE (i.e. of length 1), using

	if(Cond) A else B

instead of

	ifelse(Cond, A, B)

is

  1. much more R - like  [[ "everything you do is a function call" ]]
     hence much more elegant

  2. considerably more efficient.

  3. :-) less typing: uses two "," less ;-)

  > require(microbenchmark)
  Loading required package: microbenchmark
  > x <- setNames(,LETTERS)
  > y <- setNames(letters, runif(letters))
  > z <- pi
  > microbenchmark(r1 <- ifelse(z > 3, x, y), r2 <- if(z > 3) x else y, times=1000)
  Unit: nanoseconds
			expr  min     lq     mean median     uq   max neval cld
   r1 <- ifelse(z > 3, x, y) 4466 4971.5 5498.928   5244 5673.5 31705  1000   b
   r2 <- if (z > 3) x else y  171  212.0  265.241    264  291.0  3130  1000  a 
  > 

i.e., roughly a factor of 20 times more efficient


Martin Maechler,
ETH Zurich and R Core Team.


    > At 08:43 AM 12/14/2014, Ben Tupper wrote:
    >> Hi,
    >> 
    >> Does this work for you?  It simply tests if the name Fisher is found 
    >> among the names of the elements of spec.
    >> 
    >> obj = list(spec = list)
    >> Fisher <- ifelse(!("Fisher" %in% names(obj$spec)), FALSE, obj$spec$Fisher)
    >> 
    >> Cheers,
    >> Ben
    >> 
    >> On Dec 14, 2014, at 8:07 AM, Steven Yen <syen04 at gmail.com> wrote:
    >> 
    >> > My obj does not always come with a logical variable defined. So I do
    >> >
    >> > my.foo <- function(obj,df,digits=5){
    >> > if (!is.na("obj$spec$Fisher")) Fisher<-obj$spec$Fisher
    >> > ...
    >> > }
    >> >
    >> > This works when "Fisher" is defined in/passed from obj. When it 
    >> is not, I get error:
    >> >
    >> > Error in (!is.na("obj$spec$Fisher")) & Fisher :
    >> >  operations are possible only for numeric, logical or complex types
    >> >
    >> > I tried exist(Fisher), missing(Fisher)... to no vail. Any idea? Thanks.



More information about the R-help mailing list