Передача аргумента elipsis для оценки в вызове функции в Reduce - PullRequest
0 голосов
/ 30 декабря 2018

Фон

У меня есть забавная функция, которая сравнивает векторы в списке, используя all.equal.Поскольку я использую all.equal, я бы хотел передать соответствующие all.equal аргументы через многоточие.Без необходимости передавать что-либо в all.equal функция работает как нужно.

Цели функции

  • Функция предназначена для предоставления модифицированной версии вызова all.equal, работающего с любым числомвекторы
  • Каждый из векторов может иметь любое количество элементов;однако, если все векторы не имеют одинаковую длину, функция вернет false.
  • Функция должна иметь возможность использовать аргументы, доступные в all.equal.Например, векторы c(1.1, 2), c(1, 2) и c(1.3, 2) будут считаться равными, если указан аргумент tolerance с правильным значением. Вопрос касается того, как заставить это работать.

Пример

Сравнение 1000 векторов, каждый из которых состоит из трех целых чисел.

    compare_multiple_vectors(x = lapply(
              X = vector(mode = "list", length = 1e3),
              FUN = function(...) {
                  c(1, 2, 3)
              }
          ))

    # [1] TRUE

Проблема / желаемые результаты

all.equal, вызванные с tolerance = 1 в следующем списке векторов, вернут ожидаемые TRUE

all.equal(c(1,2), c(1,1), tolerance = 1)
# [1] TRUE

tolerance = 1аргумент не может быть отфильтрован внутри Reduce.

compare_multiple_vectors(x = list(c(1,2), c(1,1)), tolerance = 1)
# [1] FALSE

желаемый результат должен быть TRUE.


Код

#' @title Compare Values of Multiple Vectors
#'
#' @description The function compares values across multiple vectors using
#'   \code{\link[base]{all.equal}}.
#'
#' @param x Alist of vectors to compare
#' @param ... as in  \code{\link[base]{all.equal}}
#'
#' @return A logical
#'
#' @export
#'
#' @importFrom checkmate assert_atomic_vector
#'
#' @examples
#' # Returns TRUE
#' compare_multiple_vectors(c(1,1,1), c(1,1,1))
#' # Returns FALSE
#' compare_multiple_vectors(c(1,1,1), c(1,1,1), c(1,2,1))
#' # Returns FALSE
#' compare_multiple_vectors(c(1,2,3), c(3,2,1))
compare_multiple_vectors <- function(x, ...) {
    # Check if all elements of x are atomic vectors
    Vectorize(FUN = checkmate::assert_atomic_vector,
              vectorize.args = "x")(x)

    # Compare list elements
    Reduce(
        f = function(a, b, ...) {
            if (isTRUE(all.equal(target = a, current = b, ...))) {
                a
            } else {
                FALSE
            }
        },
        x = x
    ) -> res_red

    # Return results
    if (isFALSE(res_red)) {
        return(FALSE)
    } else {
        return(TRUE)
    }
}

Примечания

  • Мне интересно использовать многоточие и оставить исходный вызов таким, какой он есть с

    compare_multiple_vectors(x = list_of_vectors_to_compare, 
                             ... # all.equal arguments
                             )
    

1 Ответ

0 голосов
/ 30 декабря 2018

Я думаю, просто нужно немного изменить:

compare_multiple_vectors <- function(x, ...) {
    # Check if all elements of x are atomic vectors
    Vectorize(FUN = checkmate::assert_atomic_vector,
              vectorize.args = "x")(x)

    # Compare list elements
    Reduce(
        f = function(a, b) {  # <===================== Remove *...*

            if (isTRUE(all.equal(target = a, current = b, ...))) {
                a
            } else {
                FALSE
            }
        },
        x = x
    ) -> res_red

    # Return results
    if (isFALSE(res_red)) {
        return(FALSE)
    } else {
        return(TRUE)
    }
}

Аргументы f из Снижение , кажется, имеет подпись как функция (х, у) .Так что Reduce будет игнорировать ... in f .Если удалить многоточие f , ... будет ссылаться из космоса и будет иметь нужный результат, который вы хотите.

...