tjebo
tjebo

Reputation: 23737

Using method from one class within method for other class

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

Answers (2)

dario
dario

Reputation: 6485

Edit: This answer is not correct.

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

Konrad Rudolph
Konrad Rudolph

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

Related Questions