93i7hdjb
93i7hdjb

Reputation: 1196

R S4 Methods Applied to List of Objects in a Class

I am a fluent, long-time R user and am starting to familiarize myself with classes and methods. I am still very new to this and working through concepts.

Specifically today I am trying to apply a method to a list of objects, all of which are in a particular, user-generated class.

Take this example:

#define car
setClass("car",
  representation(
    name = "character",
    mpg = "numeric"
  )
)

#create some cars
cars <-    lapply(1:nrow(mtcars), function(x) new("car", name = 
rownames(mtcars)[x], mpg = mtcars$mpg[x]))

##SAMPLE MPG GROWTH METHOD
setGeneric("grow.mpg", function(car) {
  standardGeneric("grow.mpg")
})

setMethod("grow.mpg",
  signature("car"),
  function(car){
    old_mpg <- car@mpg
    car@mpg <- car@mpg * .1 + car@mpg
    message(paste("growing mpg on ", car@name, " from ", old_mpg, " to 
    ", car@mpg, sep = ''))
    return(car)
  })

#APPLY METHOD
cars[[1]] <- grow.mpg(cars[[1]])
growing mpg on Mazda RX4 from 25.41 to 27.951

This successfully grows mpg by 10% on cars[[1]]:

cars[[1]]
An object of class "car"
Slot "name":
[1] "Mazda RX4"

Slot "mpg":
[1] 27.951

But applying method grow.mpg to all of cars throws the following error:

cars <- grow.mpg(cars)
Error in (function (classes, fdef, mtable)  :
  unable to find an inherited method for function ‘grow.mpg’ for 
  signature ‘"list"’

So two questions:

  1. Why is this?
  2. How do I apply grow.mpg to all of cars?

Thanks in advance!

Upvotes: 1

Views: 731

Answers (1)

MrFlick
MrFlick

Reputation: 206197

You've defined your grow.mpg function for objects of class "car". And class(cars[[1]]) is a "car" but class(cars) is "list".

Just like anything else in R (and not really unique to S4 classes), whenever you want to apply the same function to every element in the list and get a new list, back, you just use lapply.

cars <- lapply(cars, grow.mpg)

Upvotes: 2

Related Questions