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,437
  • 8
  • 45
  • 67

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
  • 119,032
  • 17
  • 152
  • 277
  • 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
  • 3,873
  • 2
  • 22
  • 46