Add some string to all elements of a large (16Mill) list (might be a question about apply syntax)

Viewed 43

I'm trying to get something that looks like this:

mylist <- list(c("a"), c("a", "b"), c("a","b","c"))

into something that looks like this:

list(c("y ~ a"), c("y ~ a + b"), c("y ~ a + b + c"))

for one element, I can do this:

test <- paste0("y ~ ", paste0(mylist[[3]], collapse = " + "))  
test
[1] "y ~ a + b + c"

so I thought I'd try to use an apply and that works, too:

mylistupdater <- function(X){
mylist[[X]] <- paste0("y ~ ", paste0(mylist[[X]], collapse = " + "))  
}
lapply(c(1:length(mylist)), mylistupdater)

the problem is, that my real list has 16 million entries and this is way to slow. I think I'm writing the apply function very badly, like a loop. It should not address an index but rather the list directly, right? But the examples I see online just include a simple function. How can I pass arguments to it with these two paste0() commands and with a cleaner lapply()? Or is there a data.table solution? The output could well be a column in a data.table. Speed is actually important this time.

edit: @akrun and @Rui provide great answers below that solve my problem. I now have the luxury to think about speed and here is a horserace repeating each of the answers 100,000 times on my machine:

the version with mylistupdater(mylist): Time difference of 1.072506 secs

the version with lapply(mylist, reformulate, response = "y"): Time difference of 10.5461 secs

the version with lapply(mylist, function(x) format(reformulate(x, "y"))): Time difference of 18.20975 secs

2 Answers

A lapply call do what the question asks for. Then, assign the result back to the regressors list or to a results list.

mylistupdater <- function(X, response = "y"){
  lapply(X, function(x) {
    x <- paste(x, collapse = " + ")
    paste(response, x, sep = " ~ ")
  })
}

mylistupdater(mylist)
#[[1]]
#[1] "y ~ a"
#
#[[2]]
#[1] "y ~ a + b"
#
#[[3]]
#[1] "y ~ a + b + c"

We can use reformulate

lapply(mylist, reformulate, response = "y")

If it needs to be a string

lapply(mylist, function(x) format(reformulate(x, "y")))
#[[1]]
#[1] "y ~ a"

#[[2]]
#[1] "y ~ a + b"

#[[3]]
#[1] "y ~ a + b + c"
Related