¿Cómo asignar desde una función que devuelve más de un valor?

Resuelto mariotomo asked hace 54 años • 17 respuestas

Todavía estoy intentando entrar en la lógica de R... ¿cuál es la "mejor" manera de descomprimir (en LHS) los resultados de una función que devuelve múltiples valores?

Aparentemente no puedo hacer esto:

R> functionReturningTwoValues <- function() { return(c(1, 2)) }
R> functionReturningTwoValues()
[1] 1 2
R> a, b <- functionReturningTwoValues()
Error: unexpected ',' in "a,"
R> c(a, b) <- functionReturningTwoValues()
Error in c(a, b) <- functionReturningTwoValues() : object 'a' not found

¿Realmente debo hacer lo siguiente?

R> r <- functionReturningTwoValues()
R> a <- r[1]; b <- r[2]

¿O el programador de R escribiría algo más como esto?

R> functionReturningTwoValues <- function() {return(list(first=1, second=2))}
R> r <- functionReturningTwoValues()
R> r$first
[1] 1
R> r$second
[1] 2

--- editado para responder las preguntas de Shane ---

Realmente no necesito dar nombres a las partes del valor del resultado. Estoy aplicando una función agregada al primer componente y otra al segundo componente ( miny max... si fuera la misma función para ambos componentes, no necesitaría dividirlos).

mariotomo avatar Jan 01 '70 08:01 mariotomo
Aceptado

(1) list[...]<- Publiqué esto hace más de una década en r-help . Desde entonces se ha agregado al paquete gsubfn. No requiere un operador especial, pero sí requiere que el lado izquierdo se escriba list[...]así:

library(gsubfn)  # need 0.7-0 or later
list[a, b] <- functionReturningTwoValues()

Si solo necesita el primer o segundo componente, todos estos también funcionan:

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

(Por supuesto, si solo necesita un valor, entonces functionReturningTwoValues()[[1]]o functionReturningTwoValues()[[2]]sería suficiente).

Consulte el hilo de ayuda de r-help citado para obtener más ejemplos.

(2) con Si la intención es simplemente combinar los múltiples valores posteriormente y se nombran los valores de retorno, entonces una alternativa simple es usar with:

myfun <- function() list(a = 1, b = 2)

list[a, b] <- myfun()
a + b

# same
with(myfun(), a + b)

(3) adjuntar Otra alternativa es adjuntar:

attach(myfun())
a + b

AGREGADO: withyattach

G. Grothendieck avatar Feb 28 '2013 16:02 G. Grothendieck

De alguna manera me topé con este ingenioso truco en Internet... No estoy seguro de si es desagradable o hermoso, pero te permite crear un operador "mágico" que te permite descomprimir múltiples valores de retorno en su propia variable. La :=función se define aquí y se incluye a continuación para la posteridad:

':=' <- function(lhs, rhs) {
  frame <- parent.frame()
  lhs <- as.list(substitute(lhs))
  if (length(lhs) > 1)
    lhs <- lhs[-1]
  if (length(lhs) == 1) {
    do.call(`=`, list(lhs[[1]], rhs), envir=frame)
    return(invisible(NULL)) 
  }
  if (is.function(rhs) || is(rhs, 'formula'))
    rhs <- list(rhs)
  if (length(lhs) > length(rhs))
    rhs <- c(rhs, rep(list(NULL), length(lhs) - length(rhs)))
  for (i in 1:length(lhs))
    do.call(`=`, list(lhs[[i]], rhs[[i]]), envir=frame)
  return(invisible(NULL)) 
}

Con eso en la mano, puedes hacer lo que buscas:

functionReturningTwoValues <- function() {
  return(list(1, matrix(0, 2, 2)))
}
c(a, b) := functionReturningTwoValues()
a
#[1] 1
b
#     [,1] [,2]
# [1,]    0    0
# [2,]    0    0

No sé cómo me siento al respecto. Quizás le resulte útil en su espacio de trabajo interactivo. Usarlo para crear bibliotecas (re)utilizables (para consumo masivo) puede no ser la mejor idea, pero supongo que eso depende de usted.

... ya sabes lo que dicen sobre la responsabilidad y el poder ...

Steve Lianoglou avatar Dec 01 '2009 23:12 Steve Lianoglou

Por lo general, envuelvo la salida en una lista, que es muy flexible (puede tener cualquier combinación de números, cadenas, vectores, matrices, matrices, listas, objetos en la salida)

asi como:

func2<-function(input) {
   a<-input+1
   b<-input+2
   output<-list(a,b)
   return(output)
}

output<-func2(5)

for (i in output) {
   print(i)
}

[1] 6
[1] 7
Federico Giorgi avatar Dec 01 '2009 15:12 Federico Giorgi