R中是否有内置函数或(流行)包返回特定的列表元素或默认值?
示例:
> l <- list(a=1, b=2, c=3)
> getElementOrDefault(l, 'b', 0)
[1] 2
> getElementOrDefault(l, 'd', 0)
[1] 0
我正在寻找getElementOrDefault
的实际名称。
我知道从头开始编写这样的函数并不难,但使用内置函数有其优点。所以请不要写getElementOrDefault
的代码来回答。
答案 0 :(得分:5)
tl; dr: 没有内置的解决方案,但R更自然地为扩展其访问者语法而不是替换它。如果你不耐烦,请跳到水平分隔符之后。
使用内置有其优势
这是一个公平的观点(正如你在评论中所解释的那样),但由于似乎没有默认值,因此这一点是没有实际意义的。但是,我们可以稍微小心地定义这样的操作,使其行为与内置操作的行为方式相同。
最简单的说,我们只需将索引转发给[[
运算符 - 内置 - 从而避免因必须处理不同类型的索引而引起的所有复杂情况:< / p>
item_or_default = function (list, item, default = NULL) {
value = list[[item]]
if (is.null(value)) default else value
}
这里唯一需要注意的是,通过[[
建立索引通常是递归的,但在这里我们只支持单个索引。
这种方法无法区分缺失值和NULL
,因为内置索引操作也没有区分。这可以通过检查索引是否超出边界(如果它是数字)来修复,或者如果索引是字符串则是否缺失。该实现留给读者练习。
作为替代方案,我们可以覆盖现有的[[
运算符,并通过default
参数对其进行扩充:
`[[` = function (x, ...) {
`[[` = previous_definition('[[')
if (class(x) != 'list')
return(x[[...]])
# NB: length of index can be > 1, to allow for recursive indexing.
args = list(...)
default = args$default
args$default = NULL
value = do.call(`[[`, c(list(x), args))
if (is.null(value)) default else value
}
previous_definition = function (name) {
# Skip the parent environment of the calling frame.
get(name, envir = parent.env(parent.env(parent.frame())))
}
这大部分都是直截了当的。请注意,我们必须根据x
的类型手动调度操作符,因为覆盖[[.list
不起作用(即使文档声称运算符是通用的)。 previous_definition
为我们提供了[[
的先前定义,忽略了重新定义。因此,我们避免递归地调用相同的函数。
有意定义函数,使default
参数必须命名为,以允许递归索引,并避免混淆。举个例子:
test = list(a = 1)
test[['a', default = 42]]
# 1
test[['b', default = 42]]
# 42
test[['a', 42]]
# Error …: Incorrect number of subscripts
但最后,所有这些解决方案都有点奇怪。我不会在实际代码中使用它们中的任何一个。相反,我使用以下内容:
`%or%` = function(a, b) {
cmp = function(a,b) if (identical(a, FALSE) ||
is.null(a) ||
is.na(a) ||
is.nan(a) ||
length(a) == 0) b else a
if (length(a) > 1)
mapply(cmp, a, b)
else
cmp(a, b)
}
这允许我编写以下代码(以及更多):
test$a %or% 42
# 1
test$b %or% 42
# 42