2016-12-05 9 views
0

У меня есть функция, которая позволяет много аргументов, и чтобы упростить задачу, я решил включить другую переменную, где аргументы вводятся в виде списка (в приведенном ниже примере - args).Перезаписать аргументы внутри функции

foo <- function(x, a, b, c, args, ...) { 

ifelse(missing(a)==TRUE, a<-1, NA) 
ifelse(missing(b)==TRUE, b<-2, NA) 
ifelse(missing(c)==TRUE, c<-3, NA) 

if(missing(args)==FALSE) { 
for(i in 1:length(args)) { 
    tmp <- as.vector(args[[i]]) 
    assign(names(args)[i], get("tmp")) 
} 
} 

# Need something that overwrites "args" when the 
# other arguments are specified 

print(list(x=x, a=a, b=b, c=c)) 

} 

И функция foo дает следующее:

foo(0) 
$x 
[1] 0 

$a 
[1] 1 

$b 
[1] 2 

$c 
[1] 3 

Здесь my_args записывает аргументы профиля.

my_args <- list(a=1, b=1, c=1) 

производить:

foo(0, args=my_args) 
$x 
[1] 0 

$a 
[1] 1 

$b 
[1] 1 

$c 
[1] 1 


Я хотел бы найти способ, чтобы перезаписать значения в args всякий раз, когда соответствующие аргументы указаны в функции. Хотя пользователь указал два разных значения для одного и того же аргумента, есть обстоятельства, в которых это имеет смысл.

Например,

foo(0, args=my_args, c=3) 
$x 
[1] 0 

$a 
[1] 1 

$b 
[1] 1 

$c 
[1] 3 

И это, чтобы увидеть, что происходит, когда c=3 в профиле, записанной в my_args.

Я очень ценю некоторую помощь.

+0

простая мысль, имеющий дополнительный, если() проверяет, если оба (а/б/с или арг) не являются пропавшими без вести и затем установить в соответствии с вас выбор. –

+1

@ joel.wilson Я пробовал несколько условных обозначений, включая 'if (! (Существует (имена (args) [i])))' и 'if (missing (substitute (names (args) [i])))' без успеха , но я увижу с опцией оба (a/b/c или args). Спасибо – JARO

+0

Я бы определил 'function (x, a = NA, b = NA, c = NA, args = list (a = a, b = b, c = c), ...)' и использовать только 'args 'в функции. – Roland

ответ

1

Это позволяет аргументы передаются через args списка или с помощью ... в этом случае они перезаписывать те в args. Если аргумент не передается ни в один из них, он принимает значение по умолчанию. Оператор stopifnot вызывает ошибку, если аргументы, отличные от перечисленных в defaults, передаются в ... или в args. Он может использоваться для предотвращения передачи дополнительных аргументов, не указанных в defaults. Альтернативно, эта строка может быть опущена вообще, чтобы разрешить неограниченные аргументы.

foo <- function(x, ..., args = list()) { 
    defaults <- list(a = -1, b = -2, c = -3, d = -4) 
    Args <- Reduce(modifyList, list(defaults, args, list(...))) 
    stopifnot(all(names(Args) %in% names(defaults))) 
    Args 
} 

foo(0, a = 1, b = 2, args = list(a = 10, c = 20)) 

дает:

$a 
[1] 1 

$b 
[1] 2 

$c 
[1] 20 

$d 
[1] -4 
+0

Это отличный вариант! Благодарю. На самом деле, открывая 'defaults <- list (a = -1, b = -2, c = -3, d = -4, ...), можно включить неограниченные аргументы типа' foo (0, a = 1 , b = 2, d = 5, args = list (a = 10, c = 20), e = 9, z = "char") ', и именно этого я и искал. – JARO

+0

Это может привести к появлению двух разных компонентов с тем же именем в 'defaults'. Вместо этого, если вы хотите неограниченные аргументы, просто опустите 'stopifnot (...)'. Я объяснил это в ответ. –

+0

Это правильно. Просто открыв «defaults» этот список _and_, будут напечатаны введенные аргументы. Теперь ваша функция работает как шарм. – JARO

1

Я не являюсь поклонником этой структуры в том смысле, что назначение значений по умолчанию для ab и c очень неясно, если посмотреть на код. Но это один из способов сделать то, что вы хотите:

foo <- function(x, a = NA, b = NA, c = NA, args = NULL, ...) { 
    if (is.null(args)) { 
    a <- ifelse(is.na(a), 1, a) 
    b <- ifelse(is.na(b), 2, b) 
    c <- ifelse(is.na(c), 3, c) 
    } else { 
    args[!is.na(c(a, b, c))] <- c(a, b, c)[!is.na(c(a, b, c))] 
    lapply(names(args), function(x) assign(x, args[[x]], inherits = TRUE)) 
    } 
    print(list(x=x, a=a, b=b, c=c)) 
} 
+0

Спасибо @Axeman за ответ. Однако 'c (a, b, c)' является просто примером, и мне нужно оценить комбинации (других) потенциальных аргументов в функции, и поток управления, по-видимому, необходим. Тем не менее, ваш код работает, и я еще раз рассмотрю этот вариант. – JARO

Смежные вопросы