【问题标题】:Passing elipsis argument to be evaluated within function call within Reduce传递省略号参数以在 Reduce 内的函数调用中进行评估
【发布时间】:2019-05-27 04:03:29
【问题描述】:

背景

我有一个有趣的函数,它使用all.equal 比较列表中的向量。当我使用all.equal 时,我想通过省略号传递相关的all.equal 参数。无需向all.equal 传递任何内容,该函数即可按需要工作。

功能目标

  • 该函数旨在提供all.equal 调用的修改版本,可处理任意数量的向量
  • 每个向量可以有任意数量的元素;但是,如果所有向量的长度不同,则该函数将返回 false。
  • 该函数应该能够利用all.equal 中可用的参数。例如,如果提供了具有正确值的 tolerance 参数,则向量 c(1.1, 2)c(1, 2)c(1.3, 2) 将被视为相等。 问题在于如何让它发挥作用。

示例

比较 1000 个向量,每个向量由三个整数组成。

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

    # [1] TRUE

问题/期望的结果

在以下向量列表中使用tolerance = 1 调用all.equal 将返回预期的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
                             )
    

【问题讨论】:

  • Reduce 没有 ... 参数,但 Map 有。像Map(function(a, b, ...) all.equal(a, b, ...), list(c(1,2)), list(c(1,1)), tolerance = 1) 这样的事情会做吗?请注意,该列表现在是两个列表。
  • 或者只是Map(all.equal, list(c(1,2)), list(c(1,1)), tolerance = 1)。显然,Map 识别了all.equal 的省略号参数。
  • @RuiBarradas 我认为这可行;这如何影响性能,因为 Reduce 将始终比较两个向量?另外,我想将一个参数作为向量列表传递给检查,对于 Map,这将不得不分解为单独的列表,具有奇数个向量的列表呢?
  • 我认为目前尚不清楚您正在尝试哪种比较以及需要哪种错误检查。我们可以假设列表中的所有条目的长度都是 2 吗?还是有些长度不同?这一切都需要一组用于测试的测试用例和一组相应的解释,为什么应该提供指定的结果。并且结果是否不需要以列表的形式而不是向量的形式? (投票结束时不清楚,但会鼓励您澄清,以便我可以推翻我的投票。)
  • @42- 感谢您查看此内容。我已经阐明了该函数应该做什么。

标签: r function functional-programming namespaces ellipsis


【解决方案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) {  # <===================== 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)
    }
}

Reduce 的参数f 似乎有一个签名,如function(x, y)。所以 Reduce 将忽略 f 中的 ...。如果去掉f的省略号,...会从外层空间引用,得到你想要的结果。

【讨论】:

  • 您和 OP 都未能证明对一系列示例的测试。怎么样:compare_multiple_vectors (c(2.4, 2) , c(1,2) , c(-.1, 2) ,tolerance=1)
  • @42- 试试compare_multiple_vectors (x=list(c(2.4, 2) , c(1,2) , c(-.1, 2)) ,tolerance=1) ?
  • 是的。为什么即使容差为 1,2.4 也应该“等于”-.1。
  • @42- 好吧,我的结果是 FALSE ,意思是 不等于
  • 当我重复它时,这就是我得到的。 compare_multiple_vectors (x=list(c(2.4, 2) , c(1,2) , c(.1, 2)) ,tolerance=1) 确实返回 TRUE,但 all.eqaul 在那个“跨度”上也是如此。我想这真的是 all.equal 的行为,它似乎不符合它的帮助页面描述,因为公差这么大。如果你对你的回答做一个小的编辑,我将能够撤销我的投票。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-01
  • 2017-07-05
  • 2015-01-26
  • 1970-01-01
  • 2019-02-01
  • 1970-01-01
相关资源
最近更新 更多