# Example 9.29: the perils of for loops

[This article was first published on

Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

A recent exchange on the R-sig-teaching list featured a discussion of how best to teach new students R. The initial post included an exercise to write a function, that given a n, will draw n rows of a triangle made up of “*”, noting that for a beginner, this may require two for loops. For example, in pseudo-code:**SAS and R**, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

for i = 1 to n for j = 1 to i print "*"

Unfortunately, as several folks (including Richard M. Heiberger and R. Michael Weylandt) noted, for loops in general are not the best way to take full advantage of R. In this entry, we review two solutions they proposed which fit within the R philosophy.

Richard’s solution uses the

`outer()`function to generate a 5×5 matrix of logical values indicating whether the column number is bigger than the row number. Next the

`ifelse()`function is used to replace

`TRUE`with

`*`.

> ifelse(outer(1:5, 1:5, `>=`), "*", " ") [,1] [,2] [,3] [,4] [,5] [1,] "*" " " " " " " " " [2,] "*" "*" " " " " " " [3,] "*" "*" "*" " " " " [4,] "*" "*" "*" "*" " " [5,] "*" "*" "*" "*" "*"

Michael’s solution uses the

`lapply()`function to call a function repeatedly for different values of

`n`. This returns a list rather than a matrix, but accomplishes the same task.

> lapply(1:5, function(x) cat(rep("*", x), "\n")) * * * * * * * * * * * * * * *

While this exercise is of little practical value, it does illustrate some important points, and provides a far more efficient as well as elegant way of accomplishing the tasks. For those interested in more, another resource is the R Inferno project of Patric Burns.

**SAS**

We demonstrate a SAS data step solution mainly to call out some useful features and cautions. In all likelihood a

`proc iml`matrix-based solution would be more elegant;

data test; array star [5] $ star1 - star5; do i = 1 to 5; star[i] = "*"; output; end; run; proc print noobs; var star1 - star5; run; star1 star2 star3 star4 star5 * * * * * * * * * * * * * * *

In particular, note the

`$`in the

`array`statement, which allows the variables to contain characters; by default variables created by an

`array`statement are numeric. In addition, note the reference to a sequentially suffixed list of variables using the single hyphen shortcut; this would help in generalizing to n rows. Finally, note that we were able to avoid a second

`do`loop (SAS’ primary iterative looping syntax) mainly by luck– the most recently generated value of a variable is saved by default. This can cause trouble, in general, but here it keeps all the previous “*”s when moving on to the next row.

**An unrelated note about aggregators**We love aggregators! Aggregators collect blogs that have similar coverage for the convenience of readers, and for blog authors they offer a way to reach new audiences. SAS and R is aggregated by R-bloggers and PROC-X with our permission, and by at least 2 other aggregating services which have never contacted us. If you read this on an aggregator that does not credit the blogs it incorporates, please come visit us at SAS and R. We answer comments there and offer direct subscriptions if you like our content. In addition, no one is allowed to profit by this work under our license; if you see advertisements on this page, the aggregator is violating the terms by which we publish our work.

To

**leave a comment**for the author, please follow the link and comment on their blog:**SAS and R**.R-bloggers.com offers

**daily e-mail updates**about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.

Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.