El lenguaje R tiene una característica ingeniosa para definir funciones que pueden tomar un número variable de argumentos. Por ejemplo, la función data.frame
toma cualquier número de argumentos, y cada argumento se convierte en los datos para una columna en la tabla de datos resultante. Ejemplo de uso:
> data.frame(letters=c("a", "b", "c"), numbers=c(1,2,3), notes=c("do", "re", "mi"))
letters numbers notes
1 a 1 do
2 b 2 re
3 c 3 mi
La firma de la función incluye puntos suspensivos, como este:
function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE,
stringsAsFactors = default.stringsAsFactors())
{
[FUNCTION DEFINITION HERE]
}
Me gustaría escribir una función que haga algo similar, tomar múltiples valores y consolidarlos en un solo valor de retorno (además de realizar algún otro procesamiento). Para hacer esto, necesito descubrir cómo "desempaquetar" los ...
argumentos de la función dentro de la función. No se como hacer esto. La línea relevante en la definición de la función de data.frame
es object <- as.list(substitute(list(...)))[-1L]
, que no puedo entender.
Entonces, ¿cómo puedo convertir los puntos suspensivos de la firma de la función en, por ejemplo, una lista?
Para ser más específico, ¿cómo puedo escribir get_list_from_ellipsis
en el código a continuación?
my_ellipsis_function(...) {
input_list <- get_list_from_ellipsis(...)
output_list <- lapply(X=input_list, FUN=do_something_interesting)
return(output_list)
}
my_ellipsis_function(a=1:10,b=11:20,c=21:30)
Editar
Parece que hay dos formas posibles de hacer esto. Son as.list(substitute(list(...)))[-1L]
y list(...)
. Sin embargo, estos dos no hacen exactamente lo mismo. (Para ver las diferencias, vea ejemplos en las respuestas). ¿Alguien puede decirme cuál es la diferencia práctica entre ellos y cuál debo usar?
list
yc
funcionan de esta manera, pero ambas son primitivas, por lo que no puedo inspeccionar fácilmente su código fuente para comprender cómo funcionan.rbind.data.frame
usa de esta manera.list(...)
es suficiente, ¿por qué las R incorporadas, comodata.frame
usar la forma más larga en suas.list(substitute(list(...)))[-1L]
lugar?data.frame
, no sé la respuesta a eso (que dijo, estoy seguro de que no es una buena razón para ello). Lo usolist()
para este propósito en mis propios paquetes y todavía no he encontrado un problema con él.Solo para agregar a las respuestas de Shane y Dirk: es interesante comparar
con
Tal como está, cualquiera de las versiones parece adecuada para sus propósitos
my_ellipsis_function
, aunque la primera es claramente más simple.fuente
Ya diste la mitad de la respuesta. Considerar
Entonces esto tomó dos argumentos
a
yb
de la llamada y lo convirtió en una lista. ¿No fue eso lo que pediste?fuente
[[1]]
. Además, me gustaría saber cómo funciona el encantamiento mágicoas.list(substitute(list(...)))
.list(...)
crea unlist
objeto basado en los argumentos. Luegosubstitute()
crea el árbol de análisis para la expresión no evaluada; Vea la ayuda para esta función. Además de un buen texto avanzado sobre R (o S). Esto no es algo trivial.[[-1L]]
parte (de mi pregunta)? ¿No debería ser[[1]]
?print(c(1:3)[-1])
, imprimirá solo 2 y 3. EstaL
es una nueva forma de asegurarse de que termine como un entero, esto se hace mucho en las fuentes R.[[1]]
y los$a
índices me hizo pensar que las listas anidadas estaban involucradas. Pero ahora veo que lo que realmente obtienes es la lista que quiero, pero con un elemento adicional al frente. Entonces,[-1L]
tiene sentido. ¿De dónde viene ese primer elemento extra? ¿Y hay alguna razón por la que debería usar esto en lugar de simplementelist(...)
?Esto funciona como se esperaba. La siguiente es una sesión interactiva:
Lo mismo, excepto con un argumento predeterminado:
Como puede ver, puede usar esto para pasar argumentos 'adicionales' a una función dentro de su función si los valores predeterminados no son lo que desea en un caso particular.
fuente