我的直觉是这是对R
语言的滥用,这是有很好的理由不发生的。但我发现这是我试图调试的代码中潜在错误的永久来源:
兆瓦
list.1 <- list(a=1,b=2,c=list(d=3))
list.2 <- list(b=4,c=list(d=6,e=7))
input.values <- list(list.1,list.2)
do.something.to.a.list <- function(a.list) {
a.list$b <- a.list$c$d + a.list$a
a.list
}
experiment.results <- lapply(input.values,do.something.to.a.list)
use.results.in.some.other.mission.critical.way <- function(result) {
result <- result^2
patient.would.survive.operation <- mean(c(-5,result)) >= -5
if(patient.would.survive.operation) {
print("Congrats, the patient would survive! Good job developing a safe procedure.")
} else {
print("Sorry, the patient won't make it.")
}
}
lapply(experiment.results, function(x)
use.results.in.some.other.mission.critical.way(x$b))
YES我知道这是一个愚蠢的例子,我可以在尝试访问它之前添加一个检查元素的存在。但我并不是想知道,如果我一直有完美的记忆力和意识,我能做些什么,慢慢地解决这个功能不方便、让我头疼的事实。我试图完全避免这个令人头痛的问题,也许以牺牲代码速度为代价。
所以:我想知道的是…
(a)这是可能的吗?我最初的尝试失败了,我试图读取C
内部的"$"来理解如何正确处理参数
(b)如果是,是否有很好的理由不(或不)这样做。
基本上,我的想法是,与其编写每个依赖于列表访问的非空返回的函数来仔细检查,我可以只编写一个函数来仔细检查,并相信其余的函数不会在未满足前提条件的情况下被调用b/c,失败的列表访问将失败-快速
您几乎可以覆盖R中的任何内容(除了某些特殊值- NULL
, NA
, NA_integer_
NA_real_
NA_complex_
, NA_character_
, NaN
, Inf
, TRUE
, FALSE
,据我所知)。
对于您的具体情况,您可以这样做:
`$` <- function(x, i) {
if (is.list(x)) {
i_ <- deparse(substitute(i))
x_ <- deparse(substitute(x))
if (i_ %in% names(x)) {
eval(substitute(base::`$`(x, i)), envir = parent.frame())
} else {
stop(sprintf(""%s" not found in `%s`", i_, x_))
}
} else {
eval(substitute(base::`$`(x, i)), envir = parent.frame())
}
}
`[[` <- function(x, i) {
if (is.list(x) && is.character(i)) {
x_ <- deparse(substitute(x))
if (i %in% names(x)) {
base::`[[`(x, i)
} else {
stop(sprintf(""%s" not found in `%s`", i, x_))
}
} else {
base::`[[`(x, i)
}
}
的例子:
x <- list(a = 1, b = 2)
x$a
#[1] 1
x$c
#Error in x$c : "c" not found in `x`
col1 <- "b"
col2 <- "d"
x[[col1]]
#[1] 2
x[[col2]]
#Error in x[[col2]] : "d" not found in `x`
这会使你的代码变慢很多:
microbenchmark::microbenchmark(x$a, base::`$`(x, a), times = 1e4)
#Unit: microseconds
# expr min lq mean median uq max neval
# x$a 77.152 81.398 90.25542 82.814 85.2915 7161.956 10000
# base::`$`(x, a) 9.910 11.326 12.89522 12.033 12.3880 4042.646 10000
我将此限制为list
s(将包括data.frame
s),并通过数字和字符向量实现[[
的选择,但这可能不完全代表$
和[[
可以使用的方式。
注意对于[[
,您可以使用@rawr的更简单的代码:
`[[` <- function(x, i) if (is.null(res <- base::`[[`(x, i))) simpleError('NULL') else res
,但这将抛出一个错误,如果列表的成员是NULL
,而不是没有定义。例如
x <- list(a = NULL, b = 2)
x[["a"]]