0

I want to store different output variables that are calculated inside a function. I coded a toy example:

f = function(number) 
{

  xx = NULL
  savexx = NULL
  savexx10 = NULL
  for (i in 1:10) {
  x = number*i
  xx = c(xx,x)
  }

  save_phrase = "hello"
  savexx = xx        
  savexx10 = xx*10
  save = cbind(savexx,savexx10)

}

store = f(1)
store

But with this code it is returning only the variable save = cbind(savexx,savexx10). I would like to save all the 4 variables that are created inside this function.

Is it possible doing this without using a dataframe or a list?

Carlo
  • 587
  • 1
  • 5
  • 17
  • It is impossible. You can try to save it to a global environment but I don't think it is a good solution. What is wrong with using a `list`? – Marta Feb 05 '20 at 15:28
  • 1
    Marta your answer was very good. Nothing wrong with the list, it was just to know if there is a possibility to do this, it seems it's not. Post your answer if you can – Carlo Feb 05 '20 at 15:31

4 Answers4

3

It is impossible without a list. List would be better than a data.frame because it can store different types of variables (vector, table, plot ect.) Try to do it like here:

f = function(number) 
{

xx = NULL
savexx = NULL
savexx10 = NULL
for (i in 1:10) {
  x = number*i
  xx = c(xx,x)
}

lista <- list()

lista$save_phrase = "hello"
lista$savexx = xx        
lista$savexx10 = xx*10
lista$save = cbind(lista$savexx, lista$savexx10)

lista

}

store = f(1)

# whole list:
store

# elements of a list:
store$save_phrase
store$savexx
store$savexx10
store$save
Marta
  • 3,032
  • 3
  • 17
  • 34
2

1) list We can return the desired variables in a list.

f2 = function(number) {

    xx = NULL
    savexx = NULL
    savexx10 = NULL
    for (i in 1:10) {
      x = number*i
      xx = c(xx,x)
    }

    list(save_phrase = "hello", 
      savexx = xx,        
      savexx10 = xx*10,
      save = cbind(savexx,savexx10))

}

store = f2(1)

2) mget Another way to do this is to use mget if the returned variables have a pattern to their names as in this case:

f3 = function(number) {

    xx = NULL
    savexx = NULL
    savexx10 = NULL
    for (i in 1:10) {
      x = number*i
      xx = c(xx,x)
    }

    save_phrase = "hello"
    savexx = xx        
    savexx10 = xx*10
    save = cbind(savexx,savexx10)

    mget(ls(pattern = "save"))

}

store = f3(1)

3) gsubfn gsubfn has a facility for placing the list components into separate variables. After this is run save_phrase, savexx, savexx10 and save will exists as separate variables.

library(gsubfn)
list[save_phrase, savexx, savexx10, save] <- f2(1)

4) attach Although this is not really recommended you can do this:

attach(f2(1), name = "f2")

This will create an entry on the search list with the variables that were returned so we can just refer to save_phrase, savexx, savexx10 and save. We can see the entry using search() and ls("f2") and we can remove the entry using detach("f2") .

5) assign Another possibility which is not really recommended but does work is to assign the components right into a specific environment. Now save_phrase, savexx, savexx10 and save will all exist in the global environment.

list2env(f2(1), .GlobalEnv)

Similarly this will inject those variables into the current environment. This is the same as the prior line if the current environment is the global environment.

list2env(f2(1), environment())

6) Again, I am not so sure this is a good idea but we could modify f to inject the outputs right into the parent frame. After this is run save_phrase, savexx, savexx10 and save will all exist in the current environment.

f4 = function(number, env = parent.frame()) {

    xx = NULL
    savexx = NULL
    savexx10 = NULL
    for (i in 1:10) {
      x = number*i
      xx = c(xx,x)
    }

    env$save_phrase = "hello"
    env$savexx = xx
    env$savexx10 = xx*10
    env$save = cbind(savexx,savexx10)

    invisible(env)

}

f4(1)
G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341
1

R functions only return a SINGLE object. If you want multiple objects returned they have to be combined into a list or some other type of object.

Some languages like python let us do stuff like this:

a, b = mult_return_func()

But R will only return a single object. R programmers typically use lists to return multiple objects.

BHudson
  • 687
  • 4
  • 11
0

If there is no return statement, then R will return the value of the last evaluated expression in the function.

This would explain why it is returning save = cbind(savexx,savexx10).

To return multiple values you will need a list or another object because the R return function can only return a single object.

My suggestion would be to add those values to a list, return the list, and then get the variables from the list.

I hope that helps. If you'd like to read more then I suggest going to https://www.datamentor.io/r-programming/return-function/

Vendetta
  • 2,078
  • 3
  • 13
  • 31