diff --git a/concepts/loops/.meta/config.json b/concepts/loops/.meta/config.json new file mode 100644 index 00000000..8b710014 --- /dev/null +++ b/concepts/loops/.meta/config.json @@ -0,0 +1,5 @@ +{ + "authors": ["colinleach"], + "contributors": [], + "blurb": "R provides the usual looping constructs, though they are needed less often than in most languages." +} \ No newline at end of file diff --git a/concepts/loops/about.md b/concepts/loops/about.md new file mode 100644 index 00000000..70d45563 --- /dev/null +++ b/concepts/loops/about.md @@ -0,0 +1,61 @@ +# About + +## Iterating over a vector + +This is often unnecessary in R. +As discussed in other concepts, many functions will operate on entire vectors. + +However, explicit loops are sometimes unavoidable. +This is especially true when the loop body has side effects such as printing or file I/O. + +```R +> words <- c("This", "is", "a", "loop") +> for (w in words) { print(w) } # the braces are optional here +[1] "This" +[1] "is" +[1] "a" +[1] "loop" +``` + +If the numerical index is needed, use `seq_along()`. + +```R +> v <- LETTERS[1:3] +> v +[1] "A" "B" "C" + +> for (i in seq_along(v)) { print(sprintf("%s%i", v[i], i)) } +[1] "A1" +[1] "B2" +[1] "C3" +``` + +Using `i in 1:length(v)` is not recommended, as it will cause problems with length-zero vectors: the range `1:0` is equivalent to `c(1, 0)`, so the loop body will execute and probably fail. +`seq_along` is designed to handle this case correctly. + + +## `while` and `repeat` + +These work much as you might guess, based on many C-family languages. +If necessary, use `break` to exit a loop completely and `continue` to exit the current iteration. + +These three variants are equivalent and all end with `x == 0.4444...` + +```R +x <- 12 +while (x > 1) { + x <- x / 3 +} + +x <- 12 +while (TRUE) { + x <- x/3 + if (x <= 1) break +} + +x <- 12 +repeat { # no boolean clause + x <- x/3 + if (x <= 1) break +} +``` diff --git a/concepts/loops/introduction.md b/concepts/loops/introduction.md new file mode 100644 index 00000000..4fa93078 --- /dev/null +++ b/concepts/loops/introduction.md @@ -0,0 +1,60 @@ +# Introduction + +## Iterating over a vector + +This is often unnecessary in R. +As discussed in other concepts, many functions will operate on entire vectors. + +However, explicit loops are sometimes unavoidable. +This is especially true when the loop body has side effects such as printing or file I/O. + +```R +> words <- c("This", "is", "a", "loop") +> for (w in words) { print(w) } # the braces are optional here +[1] "This" +[1] "is" +[1] "a" +[1] "loop" +``` + +If the numerical index is needed, use `seq_along()`. + +```R +> v <- LETTERS[1:3] +> v +[1] "A" "B" "C" + +> for (i in seq_along(v)) {print(sprintf("%s%i", v[i], i))} +[1] "A1" +[1] "B2" +[1] "C3" +``` + +Using `i in 1:length(v)` is not recommended, as it will cause problems with length-zero vectors. +`seq_along` is designed to handle this case correctly. + +## `while` and `repeat` + +These work much as you might guess, based on many C-family languages. +If necessary, use `break` to exit a loop completely and `continue` to exit the current iteration. + +These three variants are equivalent and all end with `x == 0.4444...` + +```R +x <- 12 +while (x > 1) { + x <- x / 3 +} + +x <- 12 +while (TRUE) { + x <- x/3 + if (x <= 1) break +} + +x <- 12 +repeat { # no boolean clause + x <- x/3 + if (x <= 1) break +} +``` diff --git a/concepts/loops/links.json b/concepts/loops/links.json new file mode 100644 index 00000000..8adb307e --- /dev/null +++ b/concepts/loops/links.json @@ -0,0 +1,6 @@ +[ + { + "url": "https://intro2r.com/loops.html", + "description": "An Introduction to R: Loops" + } + ] \ No newline at end of file diff --git a/config.json b/config.json index 01ec79ac..775a1e9d 100644 --- a/config.json +++ b/config.json @@ -569,6 +569,11 @@ "uuid": "2751b6f2-7d71-4397-b063-9bf927a57756", "slug": "booleans", "name": "Booleans" + }, + { + "uuid": "d48dec37-b0fd-4193-954a-f005c72f8eb6", + "slug": "loops", + "name": "Loops" } ], "key_features": [