2017-07-21 1 views
2

Comment puis-je déclarer une valeur autre que la première de plusieurs valeurs d'arguments autorisées comme valeur par défaut (si aucune valeur n'a été transmise)?R enum alike avec match.arg: Comment choisir un élément non-premier comme valeur par défaut?

library(stats) 

center <- function(x, type = c("mean", "median", "trimmed")) { 
    type <- match.arg(type) 
    switch(type, 
     mean = mean(x), 
     median = median(x), 
     trimmed = mean(x, trim = .1)) 
} 

values <- c(100, 120, 200) 

center(values, "median") 
# [1] 120 

center(values, "mean") 
# [1] 140 

# uses the first value "mean" as the default! 
center(values) 
# [1] 140 

Je voudrais voir la valeur par défaut dans la signature de la fonction, si possible, afin de rendre la valeur par défaut explicite (visible), e. g. (! Pseudo-code non-travail) pour faire le deuxième élément de la valeur par défaut:

center <- function(x, type = c("mean", "median", "trimmed")[2]) {... 

D'autres propositions sont également les bienvenus!

PS: Je pourrais mettre la valeur par défaut toujours dans la première position, mais s'il y a un ordre logique dans la liste, je préférerais le garder (par exemple payment.frequency = c("monthly", "quarterly", "semi-annually", "annually")

+0

@RichScriven: Je veux appeler le centre (valeurs) mais je veux spécifier la 2ème valeur comme valeur par défaut dans la fonction decl aration (pas l'appel). –

Répondre

2

Vous pouvez modifier match.arg prendre la deuxième arg. valeur au lieu de la première. Il est juste une question de trouver et de remplacer cette ligne dans le corps de la fonction.

matchArg <- base::match.arg 
body(matchArg)[[c(4, 3, 2, 3)]] <- quote(return(arg[2L])) 

maintenant, nous remplacer match.arg avec notre nouvelle fonction matchArg intérieur center, et nous allons maintenant obtenir la deuxième type valeur (la médiane) par défaut.

center <- function(x, type = c("mean", "median", "trimmed")) { 
    type <- matchArg(type) 
    switch(type, 
     mean = mean(x), 
     median = median(x), 
     trimmed = mean(x, trim = .1)) 
} 

values <- c(100, 120, 200) 

center(values) 
# [1] 120 
center(values, "mean") 
# [1] 140 

Bien sûr, cela ne répond pas à vos exigences de visibilité. Mais c'est une idée.

+0

La visibilité est un souhait facultatif, mon premier favori était également de modifier 'match.arg' et d'ajouter un paramètre pour spécifier la valeur par défaut qui rendrait la valeur par défaut visible dans le corps de la fonction au moins. THX pour afficher une méthode de programmation aussi sophistiquée (en modifiant l'arbre d'analyse du corps de la fonction :-) –

+1

@ALL: Pour afficher l'AST du corps de la fonction, vous pouvez utiliser 'pryr :: call_tree (body (matchArg))' –

+1

@rich -scriven. C'est cool. En tant que point de codage mineur, vous pouvez utiliser l'indexation récursive ici dans votre deuxième ligne, en remplaçant 'body (matchArg) [[4]] [[3]] [[2]] [[3]]' par 'body (matchArg) [[c (4, 3, 2, 3)]] '. C'est une question de goût, bien sûr, mais avec moins de caractères. – lmo

1

Merci à la réponse acceptée de @RichScriven qui a montré comment modifier match.arg j'ai trouvé un moyen de annoter aussi la valeur par défaut dans la signature de la fonction (qui était un souhait facultatif dans ma question).

L'astuce consiste à "annoter" la valeur par défaut en utilisant un nom pour l'élément vectoriel:

matchArg <- base::match.arg 
body(matchArg)[[c(4, 3, 2, 3)]] <- quote(
    return(
    if ("default" %in% names(arg)) { 
     arg[["default"]] } 
    else { 
     arg[[1L]] 
    }) 
) 

center <- function(x, type = c("mean", default = "median", "trimmed")) { 
    type <- matchArg(type) 
    switch(type, 
     mean = mean(x), 
     median = median(x), 
     trimmed = mean(x, trim = .1)) 
} 

Maintenant, la valeur par défaut est le second (annoté):

> values <- c(100, 120, 200) 
> center(values, "median") 
[1] 120 
> center(values, "mean") 
[1] 140 
> center(values) 
[1] 120 

PS: Cette solution vaudrait un patch pour la base R si suffisamment d'utilisateurs pensent que cette fonctionnalité est nécessaire ...