next up previous
Next: Apply Up: Programming in S-PLUS1 Previous: Editing Functions

Loops and Logic

At this point you should be able to write straightforward functions that apply a series of command to several arguments. However, what if you want to do something more complicated?

To do something a set number of times, use a for loop, like this: for (index in range) { }

The variable used as the index takes on each value listed in the range, in order. For example, the following for loop is used to sum the numbers 1 through 10.

> total <- 0
> for(i in 1:10)
+ {
+ total <- total+i
+ }
> total
[1] 55
This also works for more complicated ranges:
> total <- 0
> for(i in c(1,2,4,5,9))
+ total <- total+i
> total
[1] 21

The following function demonstrates a more useful application of a for loop. The function stretch, described below, takes a vector and stretches it out, by repeating each element of the vector the same number of times. (The body of the function creates a blank vector, and then appends the copies of the original elements). This is sometimes useful in reformatting data. The guts of this function uses the function rep, which generates a vector containing the first argument repeated the number of times specified by the second argument.

> stretch <- function(vec, num)
+ {
+         output <- c()
+         for(i in 1:length(vec))
+                 output <- append(output, rep(vec[i], num))
+ }
> stretch(c("big bird", "oscar", "snuffleupagus"),4)
 [1] "big bird"      "big bird"      "big bird"      "big bird"
 [5] "oscar"         "oscar"         "oscar"         "oscar"
 [9] "snuffleupagus" "snuffleupagus" "snuffleupagus" "snuffleupagus"
Note that rep can be used to lengthen the data in a different way:
> rep(c("big bird", "oscar", "snuffleupagus"),4)
 [1] "big bird"      "oscar"         "snuffleupagus" "big bird"
 [5] "oscar"         "snuffleupagus" "big bird"      "oscar"
 [9] "snuffleupagus" "big bird"      "oscar"         "snuffleupagus"
An if statement looks like if (expression) { } else { }

The expression can be any logical statement, using <,>, ==, & (and), | (or), etc. If the expression evaluates to true, the part within the first set of brackets will be executed. If it is false, the else section, if one exists (it is optional) will be executed.

> x <- 1
> if(x < 1) {"x is less than one"} else {"x is greater than or equal to one"}
[1] "x is greater than or equal to one"
A while loop can do everything a for loop can do, but it can handle more general loops as well. The format is while (expression ) { }

The following function will calculate the largest integer power (greater than zero) of a positive number x which is less than y. The two if statements ensure that the value of x will work. The next two instructions initialize i and total. The while loop is the guts of this function.

> max.power <- function(x, y)
+ {
+         if(x < y & x > 0)
+                 if(x > 1) {
+                         i <- 1
+                         total <- x
+                         while(total * x < y) {
+                                 i <- i + 1
+                                 total <- total * x
+                         }
+                         i
+                 }
+                 else "Infinity"
+         else NULL
+ }
The two if statements ensure that x and y make sense in this context. The while statement keeps multiplying by x and counting how many times it has done this. In the end, i, "Infinity" or NULL is returned.

> max.power(2, 100)
[1] 6
> max.power(2, 1)
NULL
> max.power(.5, 100)
[1] "Infinity"
> max.power(-3, 100)
NULL

Question: How would you re-write max.power to return more informative messages than ``NULL'' for cases where the first argument is larger than the second, or the first argument is negative?


next up previous
Next: Apply Up: Programming in S-PLUS1 Previous: Editing Functions
Brian Junker 2002-08-26