Как я могу передать дополнительные параметры в FUN, когда я уже использую elipsis? - PullRequest
0 голосов
/ 17 января 2020

У меня есть такая функция для получения предметов.

fetchItem <- function(name, ..., FUN)
  • name : строка имени файла
  • ... : от нуля до многих частей пути или url et c что он строит полный путь за кулисами (не вдаваясь в слишком много деталей, для потребителей очень важно, чтобы они могли бросить на это все, и он просто «делает все для них»)
  • FUN : [необязательно], чтобы определить функцию «считывателя» для того, как вы хотите ее прочитать (различные функции считывателя для JSON против CSV и c, которые обрабатывают и возвращают его так, как они этого хотят).

Пока все хорошо, это работает хорошо. Но теперь у меня есть запрос, где они хотят иметь возможность передавать дополнительные параметры в читатель FUN (в основном такие опции, как, если у него есть строка заголовка, если он использует какой-то фанкий разделитель, что-то вроде этого, есть куча их они хотят поддержать). Читатель сможет обработать эти дополнительные параметры, если я смогу выяснить, как передать их через это, но я новичок в R и борюсь с синтаксисом того, как эти цепочки объединяются.

Ответы [ 2 ]

0 голосов
/ 17 января 2020

Хотя я могу представить себе, что это может быть проблематично c, одним из методов может быть использование всех безымянных аргументов для одной цели и требование, чтобы все FUN аргументы были явно названы.

Слишком упрощение того, что вы используете ... просто для объединения в путь к файлу:

fetchItem <- function(name, ..., FUN) {
  dots <- list(...)
  nms <- names(dots)
  args1 <- is.null(nms) | nms == ""
  list(
    nofunargs = c(name = name, dots[args1]),
    funargs = dots[!args1]
  )
}
str( fetchItem("foo", "bar", FUN = read.csv, stringsAsFactors = FALSE, header = TRUE) )
# List of 2
#  $ nofunargs:List of 2
#   ..$ name: chr "foo"
#   ..$     : chr "bar"
#  $ funargs  :List of 2
#   ..$ stringsAsFactors: logi FALSE
#   ..$ header          : logi TRUE

Другая альтернатива - это немного fr agile: arguments после того, как FUN= (должен быть назван) переданы в FUN, а не в первую цель.

fetchItem2 <- function(name, ..., FUN) {
  args <- as.list(sys.call())[-1]
  nms <- names(args)
  FUNind <- which(nms == "FUN")
  if (!length(FUNind)) FUNind <- length(nms) + 1L
  list(
    nofunargs = args[ seq_len(FUNind - 1L) ],
    funargs = args[ -seq_len(FUNind) ]
  )  
}
str( fetchItem2("foo", "bar", FUN = read.csv, stringsAsFactors = FALSE, header = TRUE, name = "othername") )
# List of 2
#  $ nofunargs:List of 2
#   ..$ : chr "foo"
#   ..$ : chr "bar"
#  $ funargs  :List of 3
#   ..$ stringsAsFactors: logi FALSE
#   ..$ header          : logi TRUE
#   ..$ name            : chr "othername"
0 голосов
/ 17 января 2020

Чтобы проиллюстрировать смысл моего последнего комментария выше, как насчет чего-то подобного?

do_something <- function(x, ..., FUN = NULL) {
    if (is.null(FUN)) print(x)

    # Get all additional arguments
    args <- list(...)

    # Match additional arguments that are allowed for FUN
    args_for_FUN <- NULL
    if (length(args) > 0) {
        allowed_args_for_FUN = c("na.rm")

        # Allow for partial matching
        names(args) <- sapply(names(args), function(arg)
            match.arg(arg, allowed_args_for_FUN))
        args_for_FUN <- args[names(args) %in% allowed_args_for_FUN]

    }

    # Execute FUN (if given)
    if (is.function(FUN)) do.call(FUN, c(list(x = x), args_for_FUN))
}

Давайте сделаем несколько тестов:

# Case 1: No FUN, no additional args
do_something(1:10)
# [1]  1  2  3  4  5  6  7  8  9 10

# Case 2: With FUN, no additional args
do_something(1:10, FUN = mean)
#[1] 5.5

# Case 3: With FUN, no additional args
do_something(c(1:10, NA), FUN = mean)
#[1] NA

# Case 4: With FUN, with an additional arg for FUN
do_something(c(1:10, NA), na.rm = T, FUN = mean)
#[1] 5.5
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...