0

I need to write loops where each iteration has a unique set of variable values. It is not a nested loop "for each i do (for each j do)" type problem. Below is just an example problem, what the loop is doing is not important, it is being able to use multiple variables for each iteration for the loop.

simple loop:

df <- data.frame(num = 1:5)
lookup <- data.frame(colors = c("red", "green", "blue"), 
                     pets = c("cat", "dog", "rabbit"),
                     stringsAsFactors = FALSE)
for (color in lookup$colors) {
  df[, color] <- 1
}

what I want to do (pseudo code):

for (color, pet in lookup$colors, lookup$pets) {
  df[, color] <- pet
}

The best approach I have come up with is below, but the additional r[" "] makes the code harder to read:

for (i in 1:nrow(lookup)) {
  r <- unlist(lookup[i, ])
  df[, r["colors"]] <- r["pets"]
}

df
  num red green   blue
1   1 cat   dog rabbit
2   2 cat   dog rabbit
3   3 cat   dog rabbit
4   4 cat   dog rabbit
5   5 cat   dog rabbit

I would like to know what the best generalisable approach to this kind of problem is. In many cases, you could replace the loop with a function to be called for each set of variables, but functions aren't suitable in certain cases.

8
  • You want df[lookup$colors] <- lookup$pets[col(df[lookup$colors])] this? Commented Feb 14, 2018 at 14:01
  • I'm not sure how this works? it doesn't run for me. But I am looking for a generalisable approach - which this doesn't seem to be. Commented Feb 14, 2018 at 14:11
  • Based on your example it is working for me and is generalizable as well (though it is not clear what kind of generaliation you meant) Are you trying to fill up the 'color' columns with the corresponding 'pets'? Commented Feb 14, 2018 at 14:12
  • can you show your expected output Commented Feb 14, 2018 at 14:17
  • yes, but it is just an example (possibly a misleading one). I am looking for the best way to use multiple variables in a loop. With functions you could do: myfunc <- function(color, pet) { do something with vars } and then call it mutiple times for different sets of vars e.g. myfunc("red", "dog"); myfunc("blue", "cat") etc. I would like to be able to do a similar thing but for loops, where functions can't always be used. Commented Feb 14, 2018 at 14:20

1 Answer 1

1

For your specific example, you're going at it with the right mindset. To clean it up a little and reduce the chance of bugs, you could rewrite the loop as:

for (i in seq_len(nrow(lookup))) {
  color_i <- lookup[i, "colors"]
  pet_i <- lookup[i, "pets"]
  df[[color_i]] <- pet_i
}

Not that different, but seq_len avoids problems where lookup has zero rows. In that case, 1:nrow(lookup) returns c(1, 0). And whether or not my loop's guts are easier to read is probably subjective.

In case it helps, a one-line solution to your specific problem is this:

df[, lookup[["colors"]]] <- lapply(lookup[["pets"]], rep, nrow(df))

Tangentially related

I will say your example is a special case in R where you're iteratively modifying an existing object. Most of the time, people just want to iterate over multiple vectors and store the results in a new vector. For example:

results <- list()

for (i in seq_len(nrow(lookup))) {
  color_i <- lookup[i, "colors"]
  pet_i <- lookup[i, "pets"]
  results[[i]] <- do_something(color_i, pet_i)
}

A better way to do this is with mapply:

results <- mapply(FUN = do_something, lookup[["colors"]], lookup[["pets"]])
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your answer - saving the lookup values to a var at the beginning like you suggest will definitely help in some cases, but if there are many vars, each only used once in the following code, it would be very messy. doing something with apply and assign might help, but I think that would be getting too complicated. I've clarified in the question that it is not the specific code in my examples that I am interested in - it is the general idea of having multiple vars in each loop iteration.
Then I'd suggest changing the body of the for loop into a function and using mapply. If necessary, values outside a function can be altered using <<-, but that's usually frowned upon.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.