Nested Loops

(Section 4.4)

A Flowery Meadow

Suppose that as they walk along the Yellow Brick Road, our Oz friends come upon a meadow that has flowers of the following colors:

flower_colors <- c("blue", "red", "pink", "crimson", "orange")

Wander the Meadow

The friends decide to wander through this meadow picking flowers.

  • Dorothy likes blue flowers, and wants 3 of them.
  • Tin Man likes red flowers, and wants 2 of them.
  • Scarecrow like blue flowers, and wants 2 of them.
  • Lion likes crimson flowers, and wants 5 of them.
  • Toto likes pink flowers, and wants 1 of them.
friends <- c("Dorothy", "Tin Man", "Scarecrow", "Lion", "Toto")
fav_color <- c("blue", "red", "blue", "crimson", "pink")
number_wanted <- c(3, 2, 2, 5, 1)

Task

Write a function that makes each person take turns wandering through the field until he/she has collected the desired number of his/her desired flowers.

The function should return the total number of flowers collected by everyone.

As it runs, the function should report what flowers each person collects.

Outline

for (person in people) {
  while (person_is_picking_flowers) {
    ## report on flowers picked
    ## somehow keep track of how many are picked
  }
}
## return the total flowers picked

Nested loops: loop within a loop.

Break Problem Down

Simplify the problem, at first:

Write a function that does the required work for just one person.

The One-Person Function

walk_meadow <- function(person, color, wanted, report = FALSE) {
  picking <- TRUE
  pick_count <- 0
  desired_count <- 0
  if (report) {
    cat(person, " picks flowers of the following colors: ")
  }
  while (picking) {
    picked <- sample(flower_colors, size = 1)
    pick_count <- pick_count + 1
    if (picked == color) desired_count <- desired_count + 1
    if (desired_count == wanted) picking <- FALSE
    if (report) {
      message <- ifelse(
        picking,
        paste(picked, ", ", sep = ""),
        paste(picked, ".\n\n", sep = "")
      )
      cat(message)
    }
  }
  pick_count
}

Try It Out

Let’s try it on the Quadling Boq:

walk_meadow(
  person = "Boq",
  color = "blue",
  wanted = 3,
  report = TRUE
)

The Result

Boq  picks flowers of the following colors: crimson, crimson, blue, blue, crimson, red, blue.
[1] 7

Final Function

all_walk <- function(people, favs, 
                     numbers, report) {
  total <- 0
  for (i in 1:length(people)) {
    person <- people[i]
    fav <- favs[i]
    number <- numbers[i]
    flowers_picked <- walk_meadow(
      person = person,
      color = fav,
      wanted = number,
      report = report
    )
    total <- total + flowers_picked
  }
  total
}

Recall Our Information

friends <- c("Dorothy", "Tin Man", "Scarecrow", "Lion", "Toto")
fav_color <- c("blue", "red", "blue", "crimson", "pink")
number_wanted <- c(3, 2, 2, 5, 1)

Try the Function

all_walk(
  people = friends,
  favs = fav_color,
  numbers = number_wanted,
  report = TRUE
)

Result

Dorothy  picks flowers of the following colors: orange, red, red, orange, red, pink, red, orange, crimson, red, crimson, crimson, red, crimson, orange, crimson, crimson, pink, red, red, pink, orange, crimson, orange, orange, red, orange, blue, pink, orange, blue, orange, pink, blue.

Tin Man  picks flowers of the following colors: orange, pink, red, red.

Scarecrow  picks flowers of the following colors: blue, pink, red, blue.

Lion  picks flowers of the following colors: orange, orange, red, orange, crimson, pink, crimson, crimson, red, red, blue, blue, crimson, red, red, red, blue, crimson.

Toto  picks flowers of the following colors: blue, blue, crimson, red, red, orange, orange, crimson, crimson, crimson, orange, crimson, blue, orange, blue, crimson, crimson, pink.
[1] 78

No Report

If you don’t need the reports, set report to FALSE:

all_walk(
  people = friends,
  favs = fav_color,
  numbers = number_wanted,
  report = FALSE
)
[1] 71