Aún tratando de entrar en la lógica R ... ¿cuál es la "mejor" forma de desempaquetar (en LHS) los resultados de una función que devuelve múltiples valores?
No puedo hacer esto aparentemente:
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 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 ( min
y max
si fuera la misma función para ambos componentes, no necesitaría dividirlos).
r
return-value
variable-assignment
assign
multiple-results
mariotomo
fuente
fuente
attr
valor de retorno.Respuestas:
(1) list [...] <- Lo publiqué 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 de la
list[...]
siguiente manera:Si solo necesita el primer o segundo componente, estos también funcionan:
(Por supuesto, si solo necesitara un valor, entonces
functionReturningTwoValues()[[1]]
ofunctionReturningTwoValues()[[2]]
sería suficiente).Vea el hilo de r-help citado para más ejemplos.
(2) con Si la intención es simplemente combinar los valores múltiples posteriormente y se nombran los valores de retorno, entonces se usa una alternativa simple
with
:(3) adjuntar Otra alternativa es adjuntar:
AGREGADO:
with
yattach
fuente
list
y[<-.result
como se muestra allí?De alguna manera me topé con este truco inteligente 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:Con eso en la mano, puedes hacer lo que buscas:
No sé cómo me siento al respecto. Quizás le resulte útil en su espacio de trabajo interactivo. Usarlo para construir bibliotecas (reutilizables) (para consumo masivo) podría no ser la mejor idea, pero supongo que eso depende de usted.
... sabes lo que dicen sobre responsabilidad y poder ...
fuente
:=
mucho al operador de una manera mucho más práctica :-)Por lo general, envuelvo el resultado en una lista, que es muy flexible (puede tener cualquier combinación de números, cadenas, vectores, matrices, matrices, listas, objetos en el resultado)
asi como:
fuente
Creo que esto funciona.
fuente
Creé un paquete R zeallot para abordar este problema. zeallot incluye una asignación múltiple o operador de asignación de desembalaje,
%<-%
. El LHS del operador es cualquier número de variables para asignar, construido usando llamadas ac()
. El RHS del operador es un vector, una lista, un marco de datos, un objeto de fecha o cualquier objeto personalizado con undestructure
método implementado (ver?zeallot::destructure
).Aquí hay algunos ejemplos basados en la publicación original,
Consulte la viñeta del paquete para obtener más información y ejemplos.
fuente
No hay una respuesta correcta a esta pregunta. Realmente depende de lo que estés haciendo con los datos. En el simple ejemplo anterior, sugeriría encarecidamente:
¿Es importante que los valores 1 y 2 anteriores tengan nombres? En otras palabras, ¿por qué es importante en este ejemplo que 1 y 2 se denominen a y b, en lugar de solo r [1] y r [2]? Una cosa importante para entender en este contexto es que a y b también son vectores de longitud 1. Por lo tanto, en realidad no está cambiando nada en el proceso de hacer esa asignación, aparte de tener 2 vectores nuevos que no necesitan subíndices para ser referenciado:
También puede asignar los nombres al vector original si prefiere hacer referencia a la letra que al índice:
[Editar] Dado que aplicará min y max a cada vector por separado, sugeriría usar una matriz (si a y b tendrán la misma longitud y el mismo tipo de datos) o un marco de datos (si a y b serán la misma longitud pero pueden ser diferentes tipos de datos) o use una lista como en su último ejemplo (si pueden ser de diferentes longitudes y tipos de datos).
fuente
r[1]
puede ayudar a aclarar las cosas (está bien, no si los nombres comoa
aparecen en su lugar).Las listas parecen perfectas para este propósito. Por ejemplo, dentro de la función que tendría
programa principal
fuente
Sí a su segunda y tercera pregunta: eso es lo que debe hacer, ya que no puede tener múltiples "valores" a la izquierda de una tarea.
fuente
¿Qué hay de usar asignar?
Puede pasar los nombres de la variable que desea pasar por referencia.
Si necesita acceder a los valores existentes, el inverso de
assign
esget
.fuente
r <- function() { return(list(first=1, second=2)) }
y haga referencia a los resultados usandor$first
yr$second
.Si desea devolver la salida de su función al entorno global, puede usar
list2env
, como en este ejemplo:Esta función creará tres objetos en su entorno global:
fuente
[A] Si cada uno de foo y bar es un número único, entonces no hay nada de malo en c (foo, bar); y también puede nombrar los componentes: c (Foo = foo, Bar = bar). Para que pueda acceder a los componentes del resultado 'res' como res [1], res [2]; o, en el caso mencionado, como res ["Foo"], res ["BAR"].
[B] Si foo y bar son vectores del mismo tipo y longitud, entonces nuevamente no hay nada de malo en devolver cbind (foo, bar) o rbind (foo, bar); igualmente nombrable. En el caso 'cbind', accedería a foo y bar como res [, 1], res [, 2] o como res [, "Foo"], res [, "Bar"]. También puede preferir devolver un marco de datos en lugar de una matriz:
y accede a ellos como res $ Foo, res $ Bar. Esto también funcionaría bien si foo y bar fueran de la misma longitud pero no del mismo tipo (por ejemplo, foo es un vector de números, bar un vector de cadenas de caracteres).
[C] Si foo y bar son lo suficientemente diferentes como para no combinarlos convenientemente como anteriormente, entonces definitivamente deberías devolver una lista.
Por ejemplo, su función podría ajustarse a un modelo lineal y también calcular valores pronosticados, por lo que podría tener
y luego accederías
return list(Foo=foo,Bar=bar)
al resumen como res $ Foo, los valores pronosticados como res $ Barfuente: http://r.789695.n4.nabble.com/How-to-return-multiple-values-in-a-function-td858528.html
fuente
Para obtener múltiples salidas de una función y mantenerlas en el formato deseado, puede guardar las salidas en su disco duro (en el directorio de trabajo) desde dentro de la función y luego cargarlas desde fuera de la función:
fuente
Con R 3.6.1, puedo hacer lo siguiente
fuente