0

I'd like to implement element-wise control flow. An example:

v1 = as.vector(c(1,2,3))
v2 = as.vector(c(3,2,1))
v3 = as.vector(c(0,0,1))
for (i in 1:len(c1)) {
    if (c1[i]>=2 && c2[i]<=2) {
         v3[i]=1        
    }
} 
# end result: v3 = [0,1,1]

The preferred vector form (which does not work and not efficient):

if (c1 >=2 & c2 <= 2) { 
    v3 = 1
}

Note that

v3 = c1 >=2 & c2 <= 2  # end result v3=[0,1,0] 

does not work because v3 is not supposed to change if the condition is FALSE.

What kind of vector syntax can I use to avoid the for loop? Note that if c1[i] is FALSE, c2[i] will not be examined at all.

Candy Chiu
  • 6,579
  • 9
  • 48
  • 69
  • Possible duplicate of http://stackoverflow.com/questions/6558921/r-boolean-operators-and – BadZen May 05 '15 at 15:59
  • you could use an if statement – Joshua Byer May 05 '15 at 16:04
  • if(temp = as.vector(c(tmp_f(),tmp_f()))) { temp & as.vector(c(tmp_t(),tmp_t()))} – Joshua Byer May 05 '15 at 16:04
  • @CandyChiu: Why are you trying to do this? Byers comments are simply wrong. Putting an assignment statement inside the first argument to `if` is error-one and suggesting `if`'s use as a vectorized operation is error-two. – IRTFM May 05 '15 at 16:13
  • @BadZen let me rephrase the question. – Candy Chiu May 05 '15 at 16:13
  • What do you want the values in the result vector to be, where the arguments that would have formed those results are not examined? – BadZen May 05 '15 at 16:24
  • please update with examples of c1 and c2 and the desired output. the discussion in the comments is not helping – rawr May 05 '15 at 16:26
  • @BadZen Not sure if I understood your question. But the goal is the implement control-flow And. The And is short circuited when as soon as it encounters one FALSE. In this case, if c1[i] is FALSE, "#update" won't execute regardless of the value of c2[i]. – Candy Chiu May 05 '15 at 16:28
  • Updated with more detail. – Candy Chiu May 05 '15 at 16:32

2 Answers2

1

I think you're looking for ifelse, it's a vectorized if. If your vectors are logical (e.g., T or F), you don't need to test if they're equal to TRUE, they are already either TRUE or FALSE.

c1 = as.logical(sample(c(0, 1), size = 5, replace = T))
c2 = as.logical(sample(c(0, 1), size = 5, replace = T))

c3 = ifelse(c1 & c2, "both are true", "at least one is false")

cbind(c1, c2, c3)

#      c1      c2      c3                     
# [1,] "TRUE"  "FALSE" "at least one is false"
# [2,] "FALSE" "FALSE" "at least one is false"
# [3,] "TRUE"  "TRUE"  "both are true"        
# [4,] "TRUE"  "TRUE"  "both are true"        
# [5,] "FALSE" "TRUE"  "at least one is false"

Edits:

For your v example, you can do this:

# no need to coerce vectors to vectors with as.vector()
v1 = c(1, 2, 3)
v2 = c(3, 2, 1)
v3 = c(0, 0, 1)

v3 = ifelse(v1 >= 2 & v2 <= 2, 1, v3)

If v1 is >= 2 and v2 <= 2, then 1, else return the original v3 value.

In your comments, you say this:

The And is short circuited when as soon as it encounters one FALSE. In this case, if c1[i] is FALSE, "#update" won't execute regardless of the value of c2[i].

This is correct. It's the meaning of the AND operator in computer science. If you don't like this behavior, perhaps you're looking for OR, which is coded as | (vectorized) or || (single element) in R.

Gregor Thomas
  • 136,190
  • 20
  • 167
  • 294
  • I actually want to apply the computer science logical operators on elements. – Candy Chiu May 05 '15 at 16:36
  • Good! I just couldn't read the tone in your comment: I didn't know if you were describing expected behavior or calling this out as a problem. – Gregor Thomas May 05 '15 at 16:42
  • This is helpful. I suppose there is no way to short circuit the evaluation then? – Candy Chiu May 05 '15 at 17:20
  • You could nest, maybe `ifelse(v1 >= 2, ifelse(v2 <= 2, 1, v3), v3)`. R uses lazy evaluation so things aren't evaluated unless they're needed. If you post a new question focused on this "short-circuiting the evaluation" with a use-case where it is relevant you may get better answers. – Gregor Thomas May 05 '15 at 17:58
0

Why not just:

v <- c(TRUE,TRUE,FALSE,TRUE)
if (FALSE %in% v) { ## update }
if (TRUE %in% v) { ## update , etc, can negate v if nec'y }

Of course that won't coerce to logical, you'll need to as.logical, but I think does what you want...

BadZen
  • 4,083
  • 2
  • 25
  • 48