How do I assign the results of a function that returns a list of objects?

9

In R we can make a function return more than one object through a list. But how do you assign these objects to two different variables?

Example:

f<-function(){
  primeiro<-1:10
  segundo<-11:21
  return (list(primeiro,segundo))  
}

With the above function I can assign and access the objects as follows.

d<-f()
d[1]
d[2]

But I can not assign these values to distinct variables through a list

list(a,b)<-f()

I want to assign to each variable: a and b one of the result objects of the f () function. The equivalent in Python would be:

def f():
    primeiro=range(1,11)
    segundo=range(11,20)
    return (primeiro,segundo)

(a,b)=f()        
print a
print b
    
asked by anonymous 07.03.2014 / 05:02

3 answers

3

The solution I found the simplest and most interesting was to define another binary operator (such as %<-% signaling a change of <- ) that applies assign to multiple arguments with mapply :

'%<-%' <- function(variaveis, valores) {
      mapply(assign, as.character(substitute(variaveis)[-1]), valores, MoreArgs= list(envir = parent.frame()))
      invisible()
    }

So:

list(a,b,c,d) %<-% rnorm(4)

It will generate four random variables, a , b , c, and d , with the four values of rnorm , for example.

An advantage of mapply is that it will already recycle the values if they are smaller than the variables, for example:

list(a,b,c,d) %<-% c(1,2)

It will generate a=1 , b=2 , c=1 , and d=2 , as values are recycled.

It will also handle the case of the number of values being greater than the number of variables using the last numbers of values. For example:

list(a,b,c,d,e) %<-% 1:10

You will assign values from 6 to 10 to variables.

In short, it is a binary operator with an intuitive symbol ( %<-% ), with a simple definition (only one line), and that already handles some exceptions in a natural way to R . However, I would avoid using this type of operation frequently without first testing well to see if there are other side effects or unpredictable behaviors.

    
07.03.2014 / 07:32
2

Not all programming languages offer a succinct way of assigning values to more than one variable at a time - in a way, Python is an exception.

This question in Stackoverflow in English document some of the ways to approach multiple assignment in R. If you want too much you can use something suggested there but the impression I have is that it might be worth writing in the simplest and least magical way, although it is a bit longer

d <- f()
a <- d[1]
b <- d[2]
    
07.03.2014 / 05:22
1

In this answer in SOEN the author proposes a framework to allow constructions of this type. Here is the original post (also in English). The suggested code is:

list <- structure(NA,class="result")
"[<-.result" <- function(x,...,value) {
   args <- as.list(match.call())
   args <- args[-c(1:2,length(args))]
   length(value) <- length(args)
   for(i in seq(along=args)) {
     a <- args[[i]]
     if(!missing(a)) eval.parent(substitute(a <- v,list(a=a,v=value[[i]])))
   }
   x
}

And some usage examples:

list[a, b] <- funcaoRetornandoDoisValores()
list[a] <- funcaoRetornandoDoisValores()
list[a, ] <- funcaoRetornandoDoisValores()
list[, b] <- funcaoRetornandoDoisValores()

list[QR,,QRaux]  <- qr(c(1,1:3,3:1))
list[,Green,Blue]  <- col2rgb("aquamarine")

a <- 1; b <- 2
list[a,b] <- list(b,a) # Troca a e b

require(chron)
list[Month, Day, Year] <- month.day.year(unclass(Sys.Date()))

(Note that you can get all return values, or ignore those that do not interest you)

There are several other options in the same linked question (and in the reply from @missingno) but that way was the one that in my opinion produces a cleaner code.

    
07.03.2014 / 05:39