18

Is there a way to output e.g. 2 objects without using list()?

my.fun=function(vector, index)
       {
       a=fun.a(vector, index)
       b=fun.b(vector, index)
       output=list(a,b)
       }

Or to output 2 lists of objects? Considering that I could also have:

       c=fun.a(vector, index)
       d=fun.b(vector, index)

And wanted list(a,b) and another list(c,d) for the same function.

This is just a small example for what I am looking for, my function is applied to large objects and I export them as a list, however I would like to export also an intermidiate calculation. One option would be to merge all in the same list, but I would like to know if there is another solution to this.

smci
  • 32,567
  • 20
  • 113
  • 146
Gago-Silva
  • 1,873
  • 4
  • 22
  • 46
  • 1
    It was decided that this is a duplicate question 1 year after it was asked? – Gago-Silva Feb 25 '13 at 08:38
  • 1
    you don't need to take it personally, there are many duplicates in StackOverflow and closing and marking duplicates helps keeping the site cleaner and with references to related questions. Since there are many duplicates and the review of all of them may take a long time, it is not always closed immediately. – MByD Feb 25 '13 at 09:01

4 Answers4

11

You can only return one object in a function. But you have some other options. You could assign intermediate objects to the global environment (you need to be careful not to overwrite anything) or you could pass an environment to your function and assign objects to it.

Here's an example of the latter suggestion:

fun <- function(x, env) {
  env$x2 <- x^2
  x^3
}
set.seed(21)
x <- rnorm(10)
myEnv <- new.env()
fun(x, myEnv)
#  [1]  4.987021e-01  1.424421e-01  5.324742e+00 -2.054855e+00  1.061014e+01
#  [6]  8.125632e-02 -3.871369e+00 -8.171530e-01  2.559674e-04 -1.370917e-08
myEnv$x2
#  [1] 6.288699e-01 2.727464e-01 3.049292e+00 1.616296e+00 4.828521e+00
#  [6] 1.876023e-01 2.465527e+00 8.740486e-01 4.031405e-03 5.728058e-06
Joshua Ulrich
  • 173,410
  • 32
  • 338
  • 418
  • 1
    +1 At first I thought, "hey that was my answer" and then realized your version was much more structured and well thought out than mine. – IRTFM Nov 21 '11 at 18:34
  • @DWin: yeah, I saw your answer while I was writing mine and debated whether or not to post (since they're similar). But then I thought it may be helpful to someone to hear the same thing explained in a different way. – Joshua Ulrich Nov 21 '11 at 18:51
9

I found list2env ideal for what you're describing; the trickiest bit, for me, was working out what to give for the env parameter:

f=function(){
    list(a=1,b="my string")
}

ret=f()
list2env(ret,env=environment())
#a=ret$a;b=ret$b    #Same as previous line

print(a);print(b)   #1  and "my string"
Darren Cook
  • 27,837
  • 13
  • 117
  • 217
  • You may or may not want to use `environment()`. It returns the Global Environment in this case, but only because it's the current evaluation environment. – Joshua Ulrich Jul 18 '12 at 13:40
  • To expand on what @JoshuaUlrich wrote, environment() gives you the current scope (i.e. where your local variables are being stored). This was the SO answer that helped me most in the end: http://stackoverflow.com/a/8773047/841830 – Darren Cook Jul 18 '12 at 23:47
5

The return() object needs to be one thing ... a list or a vector. Since a list can be that "one thing" and a list can hold many things of many classes, all you need to di is initialize a list structure and then push things into it until you are ready to retrun that structure to the calling anvironment.

If you want to "push" individual items into the global (or other environment), you can use <<- or assign, although that is considered ugly practice and a violation of the paradigm of functional programming.

IRTFM
  • 258,963
  • 21
  • 364
  • 487
4

I believe you are limited to using lists, but you can combine them like:

> list(list(a=1, b=2), list(c=3, d=4))
[[1]]
[[1]]$a
[1] 1

[[1]]$b
[1] 2


[[2]]
[[2]]$c
[1] 3

[[2]]$d
[1] 4
John Colby
  • 22,169
  • 4
  • 57
  • 69