问题
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.
回答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"]])
来源:https://stackoverflow.com/questions/48788983/r-multiple-loop-counter-variables