0

I'd like generate a list of data.frames inside nested loops similar to this question. In the second loop, j should be 4, then 5 but it only runs as 5. Is the error with my function or in the way I'm using nested loops?

df=data.frame(Value=c(11,4,6,10,7,2)) 

exceedance_fun= function(x,y){ 
z=case_when(
  x > y ~ "No",
  x <= y ~ paste(y,"mg/L"),
  TRUE ~ "unsure"
)
return(z)
}  

datalist = list()

for (i in 1:2) {
for (j in 4:5) {
dat=df %>%
mutate(Vio= exceedance_fun(Value,j))
dat$i <- i
datalist[[i]] <- dat 
}
}

Incorrect Output

[[1]]
Value    Vio i
1    11     No 1
2     4 5 mg/L 1  #This should be 4 mg/L
3     5 5 mg/L 1  #This should be 4 mg/L
4    10     No 1
5     7     No 1
6     2 5 mg/L 1  #This should be 4 mg/L

[[2]]
Value    Vio i
1    11     No 2
2     4 5 mg/L 2
3     5 5 mg/L 2
4    10     No 2
5     7     No 2
6     2 5 mg/L 2
W148SMH
  • 152
  • 1
  • 11
  • Here, you are comparing a vector of length 1 with >1 and expect an output of length 1. Did you meant to wrap with `all` or `any` in the function? – akrun Sep 23 '19 at 17:46
  • Here is a problem: `datalist[[i]] <- dat ` the second time through the j loop you are overwriting the value inside "datalist" – Dave2e Sep 23 '19 at 17:47
  • `j` runs for both `4` and `5`, but since `i` is the same for both, `datalist[[i]] <- dat` saves only the last one. – Gregor Thomas Sep 23 '19 at 17:49
  • If you remove the outer `for` loop you will get your expected results – dave-edison Sep 23 '19 at 17:50

1 Answers1

1

Here's how I would recommend restructuring in the general case where you are changing multiple parameters meaningfully:

params = expand.grid(i = 1:2, j = 4:5)
datalist = list()

for (k in 1:nrow(params)) {
  datalist[[k]] = df %>%
    mutate(Vio= exceedance_fun(Value,param$j[k]),
           i = params$i[k])
}

I'd also recommend using more descriptive variable names than i and j, but I can't tell what those are.


However, in this case, i doesn't really do anything, so a single for loop is probably fine:

j_vals = 4:5
datalist = list()

for (i in seq_along(j_vals)) {
  datalist[[i]] = df %>%
    mutate(Vio= exceedance_fun(Value, j_vals[i]),
           i = i)
}

Though it seems like it might be more useful to record j than i...

Gregor Thomas
  • 136,190
  • 20
  • 167
  • 294
  • This is close, but it produces a list with 4 data.frames. There should only be 2 in the list i.e. one with 4 mg/L and one with 5mg/L. Manually typing 4 and then 5 in the original code for j produces the correct output. @Gregor – W148SMH Sep 23 '19 at 17:59
  • @W148SMH See the bottom starting with *However, in this case, `i` doesn't really do anything, so a single for loop is probably fine*... – Gregor Thomas Sep 23 '19 at 18:28