[r] Interpreting "condition has length > 1" warning from `if` function

I have an array:

a <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)

and would like to implement the following function:

w<-function(a){
  if (a>0){
    a/sum(a)
  }
  else 1
}

This function would like to check whether there is any value in a larger than 0 and if yes then divide each element by the sum of the total.

Otherwise it should just record 1.

I get the following warning message:

 Warning message:
 In if (a > 0) { :
 the condition has length > 1 and only the first element will be used

How can I correct the function?

This question is related to r if-statement

The answer is


Here's an easy way without ifelse:

(a/sum(a))^(a>0)

An example:

a <- c(0, 1, 0, 0, 1, 1, 0, 1)

(a/sum(a))^(a>0)

[1] 1.00 0.25 1.00 1.00 0.25 0.25 1.00 0.25

Just adding a point to the whole discussion as to why this warning comes up (It wasn't clear to me before). The reason one gets this is as mentioned before is because 'a' in this case is a vector and the inequality 'a>0' produces another vector of TRUE and FALSE (where 'a' is >0 or not).

If you would like to instead test if any value of 'a>0', you can use functions - 'any' or 'all'

Best


if statement is not vectorized. For vectorized if statements you should use ifelse. In your case it is sufficient to write

w <- function(a){
if (any(a>0)){
  a/sum(a)
}
  else 1
}

or a short vectorised version

ifelse(a > 0, a/sum(a), 1)

It depends on which do you want to use, because first function gives output vector of length 1 (in else part) and ifelse gives output vector of length equal to length of a.


The way I cam across this question was when I tried doing something similar where I was defining a function and it was being called with the array like others pointed out

You could do something like this however for this scenarios its less elegant compared to Sven's method.

sapply(a, function(x) afunc(x))

afunc<-function(a){
  if (a>0){
    a/sum(a)
  }
  else 1
}

Use lapply function after creating your function normally.

lapply(x="your input", fun="insert your function name")

lapply gives a list so use unlist function to take them out of the function

unlist(lapply(a,w))