Le langage R a une fonctionnalité astucieuse pour définir des fonctions qui peuvent prendre un nombre variable d'arguments. Par exemple, la fonction data.frame
prend n'importe quel nombre d'arguments et chaque argument devient les données d'une colonne dans la table de données résultante. Exemple d'utilisation:
> 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 signature de la fonction comprend des points de suspension, comme ceci:
function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE,
stringsAsFactors = default.stringsAsFactors())
{
[FUNCTION DEFINITION HERE]
}
Je voudrais écrire une fonction qui fait quelque chose de similaire, en prenant plusieurs valeurs et en les consolidant en une seule valeur de retour (ainsi qu'en effectuant un autre traitement). Pour ce faire, j'ai besoin de comprendre comment "décompresser" les ...
arguments de la fonction dans la fonction. Je ne sais pas comment faire ça. La ligne pertinente dans la définition de fonction dedata.frame
est object <- as.list(substitute(list(...)))[-1L]
, dont je ne peux pas comprendre.
Alors, comment puis-je convertir les points de suspension de la signature de la fonction en, par exemple, une liste?
Pour être plus précis, comment puis-je écrire get_list_from_ellipsis
dans le code ci-dessous?
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)
Éditer
Il semble qu'il existe deux façons possibles de procéder. Ils sont as.list(substitute(list(...)))[-1L]
et list(...)
. Cependant, ces deux ne font pas exactement la même chose. (Pour les différences, voir des exemples dans les réponses.) Quelqu'un peut-il me dire quelle est la différence pratique entre eux et laquelle je devrais utiliser?
list
etc
fonctionnent de cette manière, mais les deux sont des primitives, donc je ne peux pas facilement inspecter leur code source pour comprendre comment elles fonctionnent.rbind.data.frame
utiliser de cette façon.list(...)
est suffisant, pourquoi les fonctions intégrées R telles que l'data.frame
utilisation de la forme plus longue à laas.list(substitute(list(...)))[-1L]
place?data.frame
, je ne connais pas la réponse à cette question (qui a dit, je suis sûr qu'il y a une bonne raison pour cela). J'utiliselist()
à cette fin dans mes propres packages et je n'ai pas encore rencontré de problème avec celui-ci.Juste pour ajouter aux réponses de Shane et Dirk: il est intéressant de comparer
get_list_from_ellipsis1 <- function(...) { list(...) } get_list_from_ellipsis1(a = 1:10, b = 2:20) # returns a list of integer vectors $a [1] 1 2 3 4 5 6 7 8 9 10 $b [1] 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
avec
get_list_from_ellipsis2 <- function(...) { as.list(substitute(list(...)))[-1L] } get_list_from_ellipsis2(a = 1:10, b = 2:20) # returns a list of calls $a 1:10 $b 2:20
Dans l'état actuel des choses, les deux versions semblent adaptées à vos besoins
my_ellipsis_function
, bien que la première soit clairement plus simple.la source
Vous avez déjà donné la moitié de la réponse. Considérer
R> my_ellipsis_function <- function(...) { + input_list <- as.list(substitute(list(...))) + } R> print(my_ellipsis_function(a=1:10, b=2:20)) [[1]] list $a 1:10 $b 11:20 R>
Donc, cela a pris deux arguments
a
etb
de l'appel et l'a converti en une liste. N'est-ce pas ce que vous avez demandé?la source
[[1]]
. Aussi, j'aimerais savoir comment fonctionne l'incantation magiqueas.list(substitute(list(...)))
.list(...)
crée unlist
objet basé sur les arguments.substitute()
Crée ensuite l'arborescence d'analyse pour l'expression non évaluée; voir l'aide de cette fonction. Ainsi qu'un bon texte avancé sur R (ou S). Ce ne sont pas des choses triviales.[[-1L]]
partie (d'après ma question)? Ne devrait-il pas l'être[[1]]
?print(c(1:3)[-1])
n'imprimera que 2 et 3. LeL
est un moyen novateur de s'assurer qu'il finit par être un entier, cela se fait souvent dans les sources R.[[1]]
et les$a
indices m'a fait penser que les listes imbriquées étaient impliquées. Mais maintenant, je vois que ce que vous obtenez est la liste que je veux, mais avec un élément supplémentaire au début. Alors, ça a du[-1L]
sens. D'où vient ce premier élément supplémentaire, de toute façon? Et y a-t-il une raison pour laquelle je devrais utiliser ceci au lieu de simplementlist(...)
?Cela fonctionne comme prévu. Ce qui suit est une session interactive:
> talk <- function(func, msg, ...){ + func(msg, ...); + } > talk(cat, c("this", "is", "a","message."), sep=":") this:is:a:message. >
Idem, sauf avec un argument par défaut:
> talk <- function(func, msg=c("Hello","World!"), ...){ + func(msg, ...); + } > talk(cat,sep=":") Hello:World! > talk(cat,sep=",", fill=1) Hello, World! >
Comme vous pouvez le voir, vous pouvez l'utiliser pour passer des arguments «supplémentaires» à une fonction dans votre fonction si les valeurs par défaut ne sont pas ce que vous voulez dans un cas particulier.
la source