3

I have a list of models, and to make the code easiser to maintain (so roubst to adding and removing models) I'd like to have a single place where I store them and their names. To do this I have to solve the following naming problem.

Upstream, i have generated models in a way that's less efficient than the following (if it was this compressed, i would assign them to their own env).

lmNms <- c( "mod1", "mod2", "mod3", "mod4", "mod5", "mod6")
lapply(lmNms, function(N) assign(N, lm(runif(10) ~ rnorm(10)), env = .GlobalEnv))

Downstream, i have collected the mess into a list:

modelList <- list(mod1, mod2, mod3, mod4, mod5, mod6)

I have an (un-named) lists of variable output, and attach the names as follows:

output <- list(1, 2, 3, 4, 5, 6)
names(output) <- lmNms

I'd like to be able to use the model names from modelList:

modelList <- list(mod1, mod2, mod3, mod4, mod5, mod6)
names(output) <- someFun(modelList)

I'm sure there exists someFun -- but I cannot figure it out ... can this be done?

To be clear, the aim is to do this without using lmNms -- i want to get the names either from modelList, or have them attach at the point that i build modelList (the point is to avoid list(a = a, b=b ...) boilerplate.

ricardo
  • 8,195
  • 7
  • 47
  • 69
  • A good solution to this problem most likely lies further upstream in your code, during the creation of the models. If I were trying to address this in my own code, I would avoid creating the list of models via `list(mod1, mod2, mod3, mod4, mod5, mod6)` in the first place. But it's hard to say how you would do that without more details. – joran Jan 09 '14 at 04:46
  • It's a big job to change this aspect -- so i'd soonest not ... – ricardo Jan 09 '14 at 04:55
  • Could you give an example `mod1`,`mod2`,etc... – SethB Jan 09 '14 at 04:59
  • They are large model output objects. Similar in type to the output from the various regression functions. The point is that i want to name the elements of a list. – ricardo Jan 09 '14 at 06:49

3 Answers3

6

The key to this is to re-make the list function to stick on the names when you don't supply the names as well.

listN <- function(...){
    anonList <- list(...)
    names(anonList) <- as.character(substitute(list(...)))[-1]
    anonList
}

With this, you make modelList as follows:

modelList <- listN(mod1, mod2, mod3, mod4, mod5, mod6)

With the names attached:

R> names(modelList)
[1] "mod1" "mod2" "mod3" "mod4" "mod5" "mod6"

A fuller solution is given here, which is robust to the use of a mixture of anonymous and named arguments to list.

listN2 <- function(...){
    dots <- list(...)
    inferred <- sapply(substitute(list(...)), function(x) deparse(x)[1])[-1]
    if(is.null(names(inferred))){
        names(dots) <- inferred
    } else {
        names(dots)[names(inferred) == ""] <- inferred[names(inferred) == ""]
    }
    dots
}
Community
  • 1
  • 1
ricardo
  • 8,195
  • 7
  • 47
  • 69
1

You can do this with environments:

e <- new.env()
output <- list(1,2,3,4,5,6)
nms <- c( "mod1", "mod2", "mod3", "mod4", "mod5", "mod6")

for(i in 1:length(output)) {
    nm <- nms[i]
    e[[nm]] <- output[[i]]
}

You can reference items in the environment like any list, or coerce it to a list

> ls(e)
[1] "mod1" "mod2" "mod3" "mod4" "mod5" "mod6"
> e[['mod1']]
[1] 1
> e$mod1
[1] 1

> new_output <- as.list(e)

Since environments act a lot like lists, there is probably an easy way to do it with your original list as well.

khoxsey
  • 1,405
  • 9
  • 13
  • hmm ... a promising lead -- but my problem is that i want to get rid of the object `nms`, and to name the elements of `output` using `modelList`. – ricardo Jan 10 '14 at 19:39
1

Use sapply with simplify=FALSE. This will assign names to the result.

sapply(lmNms, get, simplify=FALSE)
Hong Ooi
  • 56,353
  • 13
  • 134
  • 187
  • I realise this seems lazy, but the aim is to __avoid__ using `lmNms`. If i do `R> sapply(c(mod1, mod2), get, simplify = F)`, i get the following error: `Error in FUN(X[[1L]], ...) : invalid first argument`. – ricardo Jan 12 '14 at 01:49