R:函数如何使用省略号(...)接受变量参数而不将其复制到内存中?

Codeola

[编辑:自R 3.1.0起,已解决了提示解决此问题的问题。]

我被要求在其他地方将其发布为一个自我回答的问题。

当R函数通过省略号参数接受任意数量的参数时,访问它们的常用方法是list(...)

f <- function(...) {
  dots <- list(...)

  # Let's print them out.
  for (i in seq_along(dots)) {
    cat(i, ": name=", names(dots)[i], "\n", sep="")
    print(dots[[i]])
  }
}

> f(10, a=20)
1: name=
[1] 10
2: name=a
[1] 20

但是,R(从v3.0.2开始)会深度复制所有list元素:

> x <- 10
> .Internal(inspect(x))
@10d85ca68 14 REALSXP g0c1 [MARK,NAM(2),TR] (len=1, tl=0) 10

> x2 <- x
> .Internal(inspect(x2))  # Not copied.
@10d85ca68 14 REALSXP g0c1 [MARK,NAM(2),TR] (len=1, tl=0) 10

> y <- list(x)
> .Internal(inspect(y[[1]]))  # x was copied to a different address:
@10dd45e88 14 REALSXP g0c1 [MARK,NAM(1),TR] (len=1, tl=0) 10

> z <- list(y)
> .Internal(inspect(z))  # y was deep-copied:
@10d889ed8 19 VECSXP g0c1 [MARK,NAM(1)] (len=1, tl=0)
  @10d889f38 19 VECSXP g0c1 [MARK,TR] (len=1, tl=0)
    @10d889f68 14 REALSXP g0c1 [MARK] (len=1, tl=0) 10

tracemem如果启用了内存分析,则也可以使用此方法进行验证

因此,您一直在将大型对象存储在中list已复制。将它们传递给在list(...)内部调用的任何函数复制:

> g <- function(...) for (x in list(...)) .Internal(inspect(x))
> g(z)  # Copied.
@10dd45e58 19 VECSXP g0c1 [] (len=1, tl=0)
  @10dd35fa8 19 VECSXP g0c1 [] (len=1, tl=0)
    @10dd36068 19 VECSXP g0c1 [] (len=1, tl=0)
      @10dd36158 14 REALSXP g0c1 [] (len=1, tl=0) 10
> g(z)  # ...copied again.
@10dd32268 19 VECSXP g0c1 [] (len=1, tl=0)
  @10d854c68 19 VECSXP g0c1 [] (len=1, tl=0)
    @10d8548d8 19 VECSXP g0c1 [] (len=1, tl=0)
      @10d8548a8 14 REALSXP g0c1 [] (len=1, tl=0) 10

还没吓到吗?尝试grep -l "list(\.\.\.)" *.R使用R库源代码。我最喜欢的是mapply/ Map,我经常调用GB的数据,想知道为什么内存用完了。至少lapply可以。

那么,如何编写带有...参数的可变参数函数并避免复制它们呢?

Codeola

我们可以...使用扩展参数match.call,然后评估并存储其中的参数,environment而不会复制值。由于environment对象要求所有元素的名称,并且不保留其顺序,因此,除了(可选)形式参数名称之外,我们还需要存储一个单独的有序标签名称向量。使用属性在这里实现:

argsenv <- function(..., parent=parent.frame()) {
  cl <- match.call(expand.dots=TRUE)

  e <- new.env(parent=parent)
  pf <- parent.frame()
  JJ <- seq_len(length(cl) - 1)
  tagnames <- sprintf(".v%d", JJ)
  for (i in JJ) e[[tagnames[i]]] <- eval(cl[[i+1]], envir=pf)

  attr(e, "tagnames") <- tagnames
  attr(e, "formalnames") <- names(cl)[-1]
  class(e) <- c("environment", "argsenv")
  e
}

现在我们可以在函数中使用它而不是list(...)

f <- function(...) {
  dots <- argsenv(...)

  # Let's print them out.
  for (i in seq_along(attr(dots, "tagnames"))) {
    cat(i, ": name=", attr(dots, "formalnames")[i], "\n", sep="")
    print(dots[[attr(dots, "tagnames")[i]]])
  }
}

> f(10, a=20)
1: name=
[1] 10
2: name=a
[1] 20

这样就可以了,但是可以避免复制吗?

g1 <- function(...) {
  dots <- list(...)
  for (x in dots) .Internal(inspect(x))
}

> z <- 10
> .Internal(inspect(z))
@10d854908 14 REALSXP g0c1 [NAM(2)] (len=1, tl=0) 10
> g1(z)
@10dcdaba8 14 REALSXP g0c1 [NAM(2)] (len=1, tl=0) 10
> g1(z, z)
@10dcbb558 14 REALSXP g0c1 [NAM(2)] (len=1, tl=0) 10
@10dcd53d8 14 REALSXP g0c1 [NAM(2)] (len=1, tl=0) 10
> 

g2 <- function(...) {
   dots <- argsenv(...);
   for (x in attr(dots, "tagnames")) .Internal(inspect(dots[[x]]))
}

> .Internal(inspect(z))
@10d854908 14 REALSXP g0c1 [MARK,NAM(2)] (len=1, tl=0) 10
> g2(z)
@10d854908 14 REALSXP g0c1 [MARK,NAM(2)] (len=1, tl=0) 10
> g2(z, z)
@10d854908 14 REALSXP g0c1 [MARK,NAM(2)] (len=1, tl=0) 10
@10d854908 14 REALSXP g0c1 [MARK,NAM(2)] (len=1, tl=0) 10

你可以在S4与插槽代替属性实现这一点,定义方法种种(length[[[c,等)它,并把它变成一个成熟的通用非复制替代list但这是另一篇文章。

旁注:您可以通过将所有此类调用重写为...来避免mapply/ ,但这工作量很大,并且对代码的美观和可读性没有任何帮助。取而代之的是,我们可以使用和一些表达式操作来重写/函数,以在内部执行以下操作:Maplapply(seq_along(v1) function(i) FUN(v1[[i]], v2[[i]],)mapplyMapargsenv

mapply2 <- function(FUN, ..., MoreArgs=NULL, SIMPLIFY=TRUE, USE.NAMES=TRUE) {
  FUN <- match.fun(FUN)

  args <- argsenv(...)
  tags <- attr(args, "tagnames")
  iexpr <- quote(.v1[[i]])
  iargs <- lapply(tags, function(x) { iexpr[[2]] <- as.name(x); iexpr })
  names(iargs) <- attr(args, "formalnames")
  iargs <- c(iargs, as.name("..."))
  icall <- quote(function(i, ...) FUN())[-4]
  icall[[3]] <- as.call(c(quote(FUN), iargs))
  ifun <- eval(icall, envir=args)

  lens <- sapply(tags, function(x) length(args[[x]]))
  maxlen <- if (length(lens) == 0) 0 else max(lens)
  if (any(lens != maxlen)) stop("Unequal lengths; recycle not implemented")

  answer <- do.call(lapply, c(list(seq_len(maxlen), ifun), MoreArgs))

  # The rest is from the original mapply code.

  if (USE.NAMES && length(tags)) {
    arg1 <- args[[tags[1L]]]
    if (is.null(names1 <- names(arg1)) && is.character(arg1)) names(answer) <- arg1
    else if (!is.null(names1)) names(answer) <- names1
  }

  if (!identical(SIMPLIFY, FALSE) && length(answer)) 
      simplify2array(answer, higher = (SIMPLIFY == "array"))
  else answer
}

# Original Map code, but calling mapply2 instead.
Map2 <- function (f, ...) {
  f <- match.fun(f)
  mapply2(FUN=f, ..., SIMPLIFY=FALSE)
}

你甚至可以为它们命名mapply/Map在你的包/全局命名空间暗影的base版本,而不必修改代码的其余部分。此处的实现仅缺少不等长循环功能,如果需要,可以添加该功能。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

在定义中使用省略号时,如何在R函数调用中捕获错误或未定义的参数

来自分类Dev

使函数对help()函数中的参数使用省略号

来自分类Dev

使用嵌套函数时,为什么 R 省略号 (...) 匹配更多参数?

来自分类Dev

如何使用自己的自定义函数(而不是vprintf等)处理可变参数(通过省略号)?

来自分类Dev

如何使用自己的自定义函数(而不是vprintf等)处理可变参数(通过省略号)?

来自分类Dev

如何让R识别省略号中的参数向量?

来自分类Dev

如何让R识别省略号中的参数向量?

来自分类Dev

R:如何在省略号中使用列表元素(如参数)?

来自分类Dev

如何将省略号的内容保存在R中以用于深度嵌套的函数调用中?

来自分类Dev

如何使用省略号传递参数并在R中的另一个环境中求值

来自分类Dev

如何避免Dplyr中的省略号...?

来自分类Dev

函数参数中的省略号是否使用与普通参数相同的调用布局

来自分类Dev

如何将省略号运算符得到的参数传递给其他函数?

来自分类Dev

如何将省略号运算符得到的参数传递给其他函数?

来自分类Dev

使用省略号作为输入变量时向函数添加描述性统计信息

来自分类Dev

嵌套函数中的省略号扩展:错误“'...'在错误的上下文中使用”

来自分类Dev

嵌套函数调用和省略号的名称相同的参数

来自分类Dev

如何理解“包含省略号的抽象声明符只能在参数声明中使用”

来自分类Dev

我如何才能在pytest中获得断言以不再使用省略号?

来自分类Dev

我如何才能在pytest中获得断言以不再使用省略号?

来自分类Dev

使用 vue-material,如何让文本换行而不是溢出到列表中的省略号?

来自分类Dev

省略项中的省略号省略

来自分类Dev

如何检测通过省略号传递的参数的大小?

来自分类Dev

考虑到省略号的出现如何计算句子

来自分类Dev

如何删除jQuery DataTables分页中的省略号?

来自分类Dev

如何从C#的堆栈跟踪中删除省略号?

来自分类Dev

使用省略号将参数传递给函数,并为某些参数(如果不存在)设置默认值

来自分类Dev

使用省略号将参数传递给函数,并为某些参数(如果不存在)设置默认值

来自分类Dev

在函数内部将省略号(dotdotdot)与dplyr :: if_else一起使用时找不到变量

Related 相关文章

  1. 1

    在定义中使用省略号时,如何在R函数调用中捕获错误或未定义的参数

  2. 2

    使函数对help()函数中的参数使用省略号

  3. 3

    使用嵌套函数时,为什么 R 省略号 (...) 匹配更多参数?

  4. 4

    如何使用自己的自定义函数(而不是vprintf等)处理可变参数(通过省略号)?

  5. 5

    如何使用自己的自定义函数(而不是vprintf等)处理可变参数(通过省略号)?

  6. 6

    如何让R识别省略号中的参数向量?

  7. 7

    如何让R识别省略号中的参数向量?

  8. 8

    R:如何在省略号中使用列表元素(如参数)?

  9. 9

    如何将省略号的内容保存在R中以用于深度嵌套的函数调用中?

  10. 10

    如何使用省略号传递参数并在R中的另一个环境中求值

  11. 11

    如何避免Dplyr中的省略号...?

  12. 12

    函数参数中的省略号是否使用与普通参数相同的调用布局

  13. 13

    如何将省略号运算符得到的参数传递给其他函数?

  14. 14

    如何将省略号运算符得到的参数传递给其他函数?

  15. 15

    使用省略号作为输入变量时向函数添加描述性统计信息

  16. 16

    嵌套函数中的省略号扩展:错误“'...'在错误的上下文中使用”

  17. 17

    嵌套函数调用和省略号的名称相同的参数

  18. 18

    如何理解“包含省略号的抽象声明符只能在参数声明中使用”

  19. 19

    我如何才能在pytest中获得断言以不再使用省略号?

  20. 20

    我如何才能在pytest中获得断言以不再使用省略号?

  21. 21

    使用 vue-material,如何让文本换行而不是溢出到列表中的省略号?

  22. 22

    省略项中的省略号省略

  23. 23

    如何检测通过省略号传递的参数的大小?

  24. 24

    考虑到省略号的出现如何计算句子

  25. 25

    如何删除jQuery DataTables分页中的省略号?

  26. 26

    如何从C#的堆栈跟踪中删除省略号?

  27. 27

    使用省略号将参数传递给函数,并为某些参数(如果不存在)设置默认值

  28. 28

    使用省略号将参数传递给函数,并为某些参数(如果不存在)设置默认值

  29. 29

    在函数内部将省略号(dotdotdot)与dplyr :: if_else一起使用时找不到变量

热门标签

归档