0

I'm writing a function that computes a new column based on several fields in my data frame. Part of the process is to do a pre-check on the range of one the input fields before actual processing. Weird thing is that my pre-check always returns the same value, that is, the outcome of the pre-check for the first row of the dataframe.

See example below with a simplified version of my function, which only includes the check. Even though the variable is properly passed to the function, and is different every time, the outcome of the pre-check stays the same. What am I missing?

> my_function = function(x){
+   print(paste(x, x < 32 && x > 0))
+   if (x < 32 && x > 0) {
+     # do_something ...
+   }
+ }
> 
> df = data.frame("A" = c(10,20,30,40), "B" = c(0,10,20,30), "C" = c(40,30,20,10))
> my_function(df$A)
[1] "10 TRUE" "20 TRUE" "30 TRUE" "40 TRUE"
> my_function(df$B)
[1] "0 FALSE"  "10 FALSE" "20 FALSE" "30 FALSE"
> my_function(df$C)
[1] "40 FALSE" "30 FALSE" "20 FALSE" "10 FALSE"
YaHaBoHo
  • 3
  • 2

1 Answers1

0

You need vectorised ifelse with a single & (instead of &&) if you want to test a condition on every element of a vector.

From ?ifelse

‘ifelse’ returns a value with the same shape as ‘test’ which is filled with elements selected from either ‘yes’ or ‘no’ depending on whether the element of ‘test’ is ‘TRUE’ or ‘FALSE’.

From ?`&&`

‘&’ and ‘&&’ indicate logical AND and ‘|’ and ‘||’ indicate logical OR. The shorter form performs elementwise comparisons in much the same way as arithmetic operators. The longer form evaluates left to right examining only the first element of each vector. Evaluation proceeds only until the result is determined. The longer form is appropriate for programming control-flow and typically preferred in ‘if’ clauses.

The short form & performs an element-wise comparison, while && evaluates only the first element of the vector.


Here is an example based on your df

f1 <- function(x) if (x < 32 && x > 0) x + 100 else x - 100;
f2 <- function(x) ifelse(x < 32 & x > 0, x + 100, x - 100);

f1(df$A)
#[1] 110 120 130 140

f2(df$A)
#[1] 110 120 130 -60
Maurits Evers
  • 42,255
  • 4
  • 27
  • 51
  • Down-voter please explain the reason for down-voting. Happy to elaborate more if my post is not clear; this *does* solve OPs question (and was accepted as an answer) so the down-vote seems unwarranted. – Maurits Evers Jul 04 '18 at 21:10
  • @RHertel I appreciate the feedback; however OPs question is *not* about how to return a `TRUE`/`FALSE` vector; if you read the question carefully you'll notice that OPs `my_function` signifies a more complex (unknown to us) routine **which requires element-wise comparison of values in a vector**; therefore the issue is in fact with `ifelse` and the use of a single `&`; in order for answers to be useful for others here on SO, they should be generalisable to different/related problems. I admit that my example was somewhat "clumsy", I'll make a change to fix that. Downvote is still unwarrated. – Maurits Evers Jul 04 '18 at 23:37