代码之家  ›  专栏  ›  技术社区  ›  Øystein S

如何在没有for循环的情况下将任意数量的参数传递给R函数?

r
  •  2
  • Øystein S  · 技术社区  · 6 年前

    我有一个元素的成对排列矩阵 A_1, A_2, ... A_N . 每一个顺序都表示为矩阵的一行。下面的代码显示了一个示例。

    # Matrix representing the relations
    # A1 < A2, A1 < A5, A2 < A4
    (mat <- matrix(c(1, 2, 1, 5, 2, 4), ncol = 2, byrow = TRUE))
    #>      [,1] [,2]
    #> [1,]    1    2
    #> [2,]    1    5
    #> [3,]    2    4
    

    我希望整个矩阵是有序对的集合。原因是我稍后需要生成这些关系的传递闭包。我一直在用 sets 打包并创建下面的函数。

    create_sets <- function(mat){
      # Empty set
      my_set <- sets::set()
    
      # For loop for adding pair elements to the set, one at a time
      for(i in seq(from = 1, to = nrow(mat), by = 1)){
        my_set <- sets::set_union(my_set, 
                                  sets::pair(mat[[i, 1]], mat[[i, 2]]))
      }
    
      return(my_set)
    }
    
    create_sets(mat)
    #> {(1, 2), (1, 5), (2, 4)}
    

    my_set2 <- sets::set(
                    sets::pair(mat[[1, 1]], mat[[1, 2]]), 
                    sets::pair(mat[[2, 1]], mat[[2, 2]]),
                    sets::pair(mat[[3, 1]], mat[[3, 2]])
    )
    
    my_set2
    #> {(1, 2), (1, 5), (2, 4)}
    

    为什么这样做,是因为 sets::set 取任意数量的对。

    args(sets::set)
    #> function (...) 
    #> NULL
    

    mat 将有任意数量的行,我希望函数能够处理所有可能的情况。这就是为什么我不能摆脱for循环。

    垫子 其中每一行表示一个有序的对,是否有某种通用的方法将每一行中的对作为单独的参数传递给 集合::集合 ,没有循环?

    2 回复  |  直到 6 年前
        1
  •  1
  •   Uwe    6 年前

    手术室问

    […]是否有某种通用方法将每行中的对作为单独的参数传递给 sets::set

    是的,那个 do.call() 功能可能是你想要的。从 help(do.call)

    do.call 从名称或函数构造并执行函数调用以及要传递给它的参数列表。

    所以,手术室 create_sets()

    do.call(sets::set, apply(mat, 1, function(x) sets::pair(x[1], x[2])))
    
    {(1, 2), (1, 5), (2, 4)}
    

    第二个论点 做。打电话() 需要一个列表。这是由

    apply(mat, 1, function(x) sets::pair(x[1], x[2]))
    

    返回列表

    [[1]]
    (1, 2)
    
    [[2]]
    (1, 5)
    
    [[3]]
    (2, 4)
    

    apply(mat, 1, FUN) for 在矩阵行上循环的循环 mat 并在调用函数时将行值的向量作为参数 FUN

    编辑: as.tuple() pair()

    这个 对() 函数只需要两个参数。这就是为什么我们被迫定义一个匿名函数 function(x) sets::pair(x[1], x[2]) .

    这个 函数将对象的元素强制为集合的元素。因此,代码可以更加简化:

    do.call(sets::set, apply(mat, 1, sets::as.tuple))
    
    {(1,2),(1,5),(2,4)}
    

    作为.tuple()

        2
  •  1
  •   twedl    6 年前

    选择1:无所事事

    因为循环并不总是世界末日,如果矩阵不是很大的话,这看起来也不算太糟。

    选项2:拆分、应用、合并方式(通过一个新函数)

    f <- function(x) {
      sets::pair(x[1], x[2])
    }
    
    Reduce(sets::set_union, lapply(split(mat, 1:nrow(mat)), f))
    ## {(1, 2), (1, 5), (2, 4)}
    

    这个 Reduce set_union ),以及 lapply 将矩阵转换为成对的列表(也像for循环一样)