请考虑以下代码段:
> a <- 1:1e7
> b <- 1:1e7
> (sizes <- sapply(c("a","b"),function(n) {
s <- object.size(get(n))
cat(n,": ")
print(s,units="auto")
}))
a : 38.1 Mb
b : 38.1 Mb
a b
40000040 40000040
> class(sizes)
[1] "numeric"
> (s <- sum(sizes))
[1] 80000080
> class(s) <- "object_size"
> s
80000080 bytes
> print(s,units="auto")
76.3 Mb
观察
sapply
从"object_size"
中移除了sizes
类,lapply
没有,但其结果 - list
- 无法传递给{ {1}})。
sum
个对象使用"object_size"
而不是units="B"
打印
两者似乎都不是最理想的; "auto"
的值应打印为
sizes
我的问题是:这只是一个错误,还是这种行为背后有一些深层原因?
答案 0 :(得分:2)
我认为这里没有任何错误。
事情的真相是R对象的类只是一个与其他属性一样的属性,当sapply
将结果简化为向量时,所有属性都被剥离。您可以通过执行此操作来解决问题,尽管输出非常难看
> class(sizes) <- "object_size"
> sizes
40000040 bytes40000040 bytes
> sum(sizes)
80000080 bytes
正如您所指出的那样lapply
会保留该类(因为它不会简化),如果您想计算结果的总和,您可以调用以下内容。
> (sizes <- lapply(c("a","b"),function(n) {
s <- object.size(get(n))
cat(n,": ")
print(s,units="auto")
}))
a : 38.1 Mb
b : 38.1 Mb
[[1]]
40000040 bytes
[[2]]
40000040 bytes
> (s <- do.call(sum, sizes))
80000080
sum
也剥离了类,因为没有定义名为"sum.object_size"
的函数,而是使用.Primitive("sum")
,这再次将其简化为数字。你可以超载它,但@Greg Snow使用Reduce
的答案更优雅。
> `sum.object_size` <- function(...){
s <- sum(unlist(list(...)))
class(s) <- "object_size"
s
}
> do.call(sum, sizes)
80000080 bytes
print.object_size
的默认行为是使用units="b"
,无论您在sapply
来电中设置了什么。如果您想默认以不同方式打印它们,则必须重载print.object_size
> print.object_size <- function(..., units="auto")
getFromNamespace("print.object_size", "utils")(..., units=units)
> sizes
[[1]]
38.1 Mb
[[2]]
38.1 Mb
编辑:请注意“已承诺评估”错误
考虑以下功能:
f <- function(x=1){
h <- function(x) x
h(x=x)
}
g <- function(x=1){
h <- function(x=x) x
h()
}
f
将在x
的环境中搜索h(x=x)
中的f
时无问题地运行。另一方面,g
会导致错误,因为x
中的h()
在h
的环境中搜索,但未定义。{/ p>
答案 1 :(得分:2)
如果要将列表的元素添加在一起,请考虑使用Reduce
函数。它将二元运算符(在本例中为+
)应用于向量或列表。 +
运算符不会删除类和sapply
和sum
等其他属性:
> a <- 1:1e7
> b <- 1:1e7
> (sizes <- lapply(c("a","b"),function(n) {
+ s <- object.size(get(n))
+ cat(n,": ")
+ print(s,units="auto")
+ }))
a : 38.1 Mb
b : 38.1 Mb
[[1]]
40000040 bytes
[[2]]
40000040 bytes
>
> Reduce('+', sizes)
80000080 bytes
> print(.Last.value, units='auto')
76.3 Mb