One handy (though somewhat wasteful) use ofwhich()is for determin-
ing the location within a vector at which the first occurrence of some condi-
tion holds. For example, recall our code on page 27 to find the first 1 value
within a vectorx:
first1 <- function(x) {
for (i in 1:length(x)) {
if (x[i] == 1) break # break out of loop
}
return(i)
}
Here is an alternative way of coding this task:
first1a <- function(x) return(which(x == 1)[1])
The call towhich()yields the indices of the 1s inx. These indices will be
given in the form of a vector, and we ask for element index 1 in that vector,
which is the index of the first 1.
That is much more compact. On the other hand, it’s wasteful, as it actu-
ally findsallinstances of 1s inx, when we need only the first. So, although it
is a vectorized approach and thus possibly faster, if the first 1 comes early in
x, this approach may actually be slower.
2.9 A Vectorized if-then-else: The ifelse() Function.................................
In addition to the usual if-then-else construct found in most languages,
R also includes a vectorized version, theifelse()function. The form is as
follows:
ifelse(b,u,v)
wherebis a Boolean vector, anduandvare vectors.
The return value is itself a vector; elementiisu[i]ifb[i]is true, orv[i]
ifb[i]is false. The concept is pretty abstract, so let’s go right to an example:
> x <- 1:10
> y <- ifelse(x %% 2 == 0,5,12) # %% is the mod operator
>y
[1] 12 5 12 5 12 5 12 5 12 5
Here, we wish to produce a vector in which there is a 5 whereverxis
even or a 12 whereverxis odd. So, the actual argument corresponding to
the formal argumentbis (F,T,F,T,F,T,F,T,F,T). The second actual argument,
5, corresponding tou, is treated as (5,5,...)(ten 5s) by recycling. The third
argument, 12, is also recycled, to (12,12,...).
48 Chapter 2