假设我有一个子集化功能(这只是一个最小的例子):
f <- function(x, ind = seq(length(x))) {
x[ind]
}
(注意:一个人只能使用seq(x)
代替seq(length(x))
,但我不太清楚。)
所以,如果
x <- 1:5
ind <- c(2, 4)
ind2 <- which(x > 5) # integer(0)
我有以下结果:
f(x)
[1] 1 2 3 4 5
f(x, ind)
[1] 2 4
f(x, -ind)
[1] 1 3 5
f(x, ind2)
integer(0)
f(x, -ind2)
integer(0)
对于最后一个结果,我们希望获得所有x
,但这是导致错误的常见原因(正如 Advanced R 一书中所提到的那样)。
所以,如果我想创建一个删除索引的函数,我使用:
f2 <- function(x, ind.rm) {
f(x, ind = `if`(length(ind.rm) > 0, -ind.rm, seq(length(x))))
}
然后我得到了我想要的东西:
f2(x, ind)
[1] 1 3 5
f2(x, ind2)
[1] 1 2 3 4 5
我的问题是:
我可以做一些更干净的事情,并且不需要在seq(length(x))
中明确传递f2
,而是直接使用默认值f
的参数ind
ind.rm
是integer(0)
?
答案 0 :(得分:2)
你所拥有的一切都不错,但如果你想避免传递默认参数的默认值,你可以像这样重组:
f2 <- function(x, ind.rm) {
`if`(length(ind.rm) > 0, f(x,-ind.rm), f(x))
}
比你的略短。
在编辑
基于这些评论,您似乎希望能够传递一个函数(而不是简单地不传递),因此它使用默认值。您可以通过编写一个设置为不接收任何内容的函数来完成此操作,也称为NULL
。您可以将f
重写为:
f <- function(x, ind = NULL) {
if(is.null(ind)){ind <- seq(length(x))}
x[ind]
}
NULL
作为一个标志,告诉接收函数使用参数的默认值,尽管必须在函数体中设置该默认值。
现在f2
可以改写为
f2 <- function(x, ind.rm) {
f(x, ind = `if`(length(ind.rm) > 0, -ind.rm, NULL))
}
这比你的可读性略高,但代价是使原始功能稍长一些。
答案 1 :(得分:2)
如果您预计会有很多“空”负面指数,那么如果您可以避免使用x[seq(x)]
而不仅仅x
使用的索引,则可以提高这些情况的效果。换句话说,如果您能够将f
和f2
合并为:
new_f <- function(x, ind.rm){
if(length(ind.rm)) x[-ind.rm] else x
}
在空负指数的情况下会有一个巨大的加速。
n <- 1000000L
x <- 1:n
ind <- seq(0L,n,2L)
ind2 <- which(x>n+1) # integer(0)
library(microbenchmark)
microbenchmark(
f2(x, ind),
new_f(x, ind),
f2(x, ind2),
new_f(x, ind2)
)
all.equal(f2(x, ind), new_f(x, ind)) # TRUE - same result at about same speed
all.equal(f2(x, ind2), new_f(x, ind2)) # TRUE - same result at much faster speed
Unit: nanoseconds
expr min lq mean median uq max neval
f2(x, ind) 6223596 7377396.5 11039152.47 9317005 10271521 50434514 100
new_f(x, ind) 6190239 7398993.0 11129271.17 9239386 10202882 59717093 100
f2(x, ind2) 6823589 7992571.5 11267034.52 9217149 10568524 63417978 100
new_f(x, ind2) 428 1283.5 5414.74 6843 7271 14969 100
答案 2 :(得分:0)
要实现“parameter1 = if(cond1)then value1 else default_value_of_param1”,我使用formals
将默认参数设为call
:
f <- function(x, ind.row = seq_len(nrow(x)), ind.col = seq_len(ncol(x))) {
x[ind.row, ind.col]
}
f2 <- function(x, ind.row.rm = integer(0), ind.col.rm = integer(0)) {
f.args <- formals(f)
f(x,
ind.row = `if`(length(ind.row.rm) > 0, -ind.row.rm, eval(f.args$ind.row)),
ind.col = `if`(length(ind.col.rm) > 0, -ind.col.rm, eval(f.args$ind.col)))
}
然后:
> x <- matrix(1:6, 2)
> f2(x, 1:2)
[,1] [,2] [,3]
> f2(x, , 1:2)
[1] 5 6
> f2(x, 1, 2)
[1] 2 6
> f2(x, , 1)
[,1] [,2]
[1,] 3 5
[2,] 4 6
> f2(x, 1, )
[1] 2 4 6
> f2(x)
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6