Reputation: 23737
I am trying to use a method for one class (data.frame) within a method for another class (list), in this case a list of several data frames.
This does not work, and I strongly assume due to some scoping problems. In my case foo.data.frame
doesn't find funs
anymore. If tried a few things to re-define funs
(see comments in code), to no avail.
So, my question would be, how could I make funs
accessible to foo.data.frame
within foo.list
. Or, are there good reasons why this is bad programming style. (I am still considering myself a programming beginner). Cheers.
update
I could define funs
in the global environment - and I am happy to do that. But is there a way to access the environment created by useMethod, kind of from within the method in the method?
set.seed(42)
mydf <- cbind(a = rep(letters[1:3], 4), setNames(as.data.frame(replicate(c(rnorm(11), NA), n = 3)), letters[24:26]))
mydf_grouped <- split(mydf, mydf$a)
foo <- function(x) {
funs <- list(
mean = function(x) mean(x, na.rm = TRUE)
)
UseMethod("foo", x)
}
foo.data.frame <- function(x, ...) {
suppressWarnings(lapply(funs, mapply, x))
}
## works
foo(mydf)
#> $mean
#> a x y z
#> NA 0.6161670 -0.4570349 0.2275039
## works with a simple function
foo.list <- function(x, ...){
lapply(x, nrow)
}
foo(mydf_grouped)
#> $a
#> [1] 4
#>
#> $b
#> [1] 4
#>
#> $c
#> [1] 4
## fails with the method for data.frames
foo.list <- function(x, ...){ ## adding funs argument does not help
# funs <- funs ## does not work
# funs <- list(
# mean = function(x) mean(x, na.rm = TRUE)
# ) ## Defining funs within foo.list does not work either
lapply(x, foo.data.frame ) ## adding funs here does also not help
}
foo(mydf_grouped)
#> Error in lapply(funs, mapply, x): object 'funs' not found
Upvotes: 1
Views: 51
Reputation: 6485
See the accepted answer above for an explanation.
If you move the foo assignement out of the method declaration into foo.data.frame it works:
set.seed(42)
mydf <- cbind(a = rep(letters[1:3], 4), setNames(as.data.frame(replicate(c(rnorm(11), NA), n = 3)), letters[24:26]))
mydf_grouped <- split(mydf, mydf$a)
foo <- function(x) {
UseMethod("foo", x)
}
foo.data.frame <- function(x, ...) {
funs <- list(
mean = function(x) mean(x, na.rm = TRUE)
)
suppressWarnings(lapply(funs, mapply, x))
}
foo.list <- function(x, ...){
lapply(x, foo.data.frame )
}
foo(mydf_grouped)
Returns:
$a $a$mean a x y z NA 0.8631572 -0.2024425 0.1406371 $b $b$mean a x y z NA 0.2624452 -1.2436714 0.3381285 $c $c$mean a x y z NA 0.7584759 0.2523572 0.1958268
Blockquote
Upvotes: 1
Reputation: 545528
The problem is that you are calling foo.data.frame
directly, and that function defines no funs
. You need to call it via the generic foo
:
foo.list <- function(x) {
lapply(x, foo)
}
This works, since foo
in lapply
will call the generic which correctly dispatches to the appropriate method (foo.data.frame
) in the case of calling it with a list of data.frames, as in foo(mydf_grouped)
.
Upvotes: 2