2

Function foo1 can subset a list by a requested variable (e.g., by = type == 1). Otherwise, foo1 will simply output the inputted list itself.

For my purposes, I need to use foo1 within a new function called foo2.

In my code below, my desired output is obtained like so: foo2(data = D, by = G[[1]]) ; foo2(data = D, by = G[[2]]) ; foo2(data = D, by = G[[3]]).

But, I wonder why when I loop over G using lapply, I get an error as shown below?

foo1 <- function(data, by){

  L <- split(data, data$study.name) ; L[[1]] <- NULL

  if(!missing(by)){

   L <- lapply(L, function(x) do.call("subset", list(x, by)))
  }
 return(L)
}


foo2 <- function(data, by){

  eval(substitute(foo1(data = data, by = by)))
}

## EXAMPLE OF USE:
D <- read.csv("https://raw.githubusercontent.com/izeh/i/master/k.csv", h = T) ## Data

G <- lapply(unique(na.omit(D$type)), function(i) bquote(type == .(i)))# all levels of `type`

foo2(data = D, by = G[[1]]) # Works fine without `lapply` :-)

lapply(1:3, function(i) foo2(data = D, by = G[[i]])) # Doesn't work with `lapply`! :-(
# Error in do.call("subset", list(x, by)) : object 'i' not found
rnorouzian
  • 7,397
  • 5
  • 27
  • 72
  • 1
    Why are you using `eval` + `substitute`? Also, consider a different variable name than `by` which is actually a function very similar to `split` (in fact `split` + `lapply`). – Parfait Oct 20 '19 at 15:48
  • Also, this appears to be an [XY Problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) where you ask help for a *y* solution but do not describe the larger *x* problem. Please give more background and explain your data input and desired results. Use of `eval`, `substitute`, `bquote` seems too much. – Parfait Oct 20 '19 at 15:50
  • The `eval` inside the function is making it more prone to bugs without specifying the environment. – akrun Oct 20 '19 at 17:33
  • @akrun, went ahead and asked a related [question on this](https://stackoverflow.com/questions/58477309/a-replacement-for-subset-for-a-list-of-data-frames-in-r)? – rnorouzian Oct 20 '19 at 22:53
  • @rnorouzian Yes, but that was based on the context. As Parfait mentioned, it could be an XY problem. – akrun Oct 21 '19 at 01:14

2 Answers2

2

Your foo2 function tries to evaluate the expression

foo1(data = D, by = G[[i]])

but it doesn't have i available. You need to evaluate G[[i]] in the anonymous function you're passing to lapply to get an expression defining the subset, and then evaluate that subset in foo2. I recommend naming that function instead of using an anonymous one; it makes debugging a lot easier.

Here's some recoding that appears to work:

Redefine foo2 to

foo2 <- function(data, by){
  by <- eval(by, envir = data)
  foo1(data = data, by = by)
}

and

foo3 <- function(i) {
    expr <- G[[i]]
    foo2(data = D, by = expr)
}

and then

lapply(1:3, foo3)

I'm not sure this does exactly what you want, but it should be close enough that you can fix it up.

user2554330
  • 37,248
  • 4
  • 43
  • 90
  • @rnorouzian ... [why](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem#comment436926_66378) are you even calling `foo2`? Why not directly call `foo1`? – Parfait Oct 20 '19 at 16:30
  • @Parfait, OP is saying s/he needs to use `foo1` indirectly. Please if you have an alternative solution, try to offer it. Apparently for OP, `foo1` is a nested function so s/he can't call it directly. –  Oct 20 '19 at 16:41
1

Instead of using lapply, here a for loop can be used

lst1 <- vector("list", length(G))
for(i in 1:3) lst1[[i]] <- foo2(data = D, by = G[[i]])

-checking

identical(lst1[[2]],  foo2(data = D, by = G[[2]]))
#[1] TRUE
identical(lst1[[3]],  foo2(data = D, by = G[[3]]))
#[1] TRUE

For the lapply part, there seems to be a conflict with i anonymous function which is also called in the G. If we use a new variable say 'j'

lst2 <- lapply(1:3, function(j) foo1(data = D, by = G[[j]]))

should work

identical(lst2[[2]], lst1[[2]])
#[1] TRUE
akrun
  • 874,273
  • 37
  • 540
  • 662
  • Hi Arun, would [this question](https://stackoverflow.com/questions/58895249/changing-a-list-of-tables-to-a-data-frame-in-r) be of interest? – rnorouzian Nov 16 '19 at 21:31