如何在lapply与Map中保持函数调用属性的一致性?
问题:在lapply中保留函数调用属性里的原始对象名称
我想把函数调用作为attr属性附加到结果中。直接调用fn()时一切正常,但用lapply()运行时,d=参数对应的属性值显示为X[[i]],而不是实际传入的df1、df2等名称,我希望看到的是df1和df2而非X[[i]]。
> fn <- \(d, x=x, y=999, ...) { + cl <- match.call() + fa <- formals(fn) + fa[length(fa)] <- NULL + ma <- setdiff(names(fa), names(cl)) + cl[ma] <- fa[ma] + cl[-c(1, 2)] <- lapply(cl[-c(1, 2)], eval, envir=parent.frame()) + # cl$d <- quote(d) + res <- d[[1]] ## so `res` depends on `d` + attr(res, 'call') <- cl + return(res) + } > > z. <- 777 > df1 <- lst$df1 > df2 <- lst$df2 > fn(df1, x=666, z=z.) [1] 1 2 3 attr(,"call") fn(d = df1, x = 666, z = 777, y = 999) > lapply(list(df1=df1, df2=df2), fn, x=666, z=z.) $df1 [1] 1 2 3 attr(,"call") FUN(d = X[[i]], x = 666, z = 777, y = 999) $df2 [1] 1 2 3 attr(,"call") FUN(d = X[[i]], x = 666, z = 777, y = 999)
这显然和之前的问题相关,我尝试了推荐的Map方法,但通用性不佳:
> Map(list(df1=df1, df2=df2), f=fn, x=666, z=z.) $df1 [1] 1 2 3 attr(,"call") (\(d, x=x, y=999, ...) { cl <- match.call() fa <- formals(fn) fa[length(fa)] <- NULL ma <- setdiff(names(fa), names(cl)) cl[ma] <- fa[ma] cl[-c(1, 2)] <- lapply(cl[-c(1, 2)], eval, envir=parent.frame()) # cl$d <- quote(d) res <- d[[1]] attr(res, 'call') <- cl return(res) })(d = dots[[1L]][[2L]], x = 666, z = 777, y = 999) $df2 [1] 1 2 3 attr(,"call") (\(d, x=x, y=999, ...) { cl <- match.call() fa <- formals(fn) fa[length(fa)] <- NULL ma <- setdiff(names(fa), names(cl)) cl[ma] <- fa[ma] cl[-c(1, 2)] <- lapply(cl[-c(1, 2)], eval, envir=parent.frame()) # cl$d <- quote(d) res <- d[[1]] attr(res, 'call') <- cl return(res) })(d = dots[[1L]][[2L]], x = 666, z = 777, y = 999)
之后我尝试了cl$d <- quote(d)、cl$d <- quote(substitute(d))、cl$d <- quote(eval(parse(text=d)))、cl$d <- quote(get(d))等方法(如代码中注释部分),但都无效。以下是cl$d <- quote(d)版本的结果:
> fn(df1, x=666, z=z.) [1] 1 2 3 attr(,"call") fn(d = d, x = 666, z = 777, y = 999) > lapply(list(df1=df1, df2=df2), fn, x=666, z=z.) $df1 [1] 1 2 3 attr(,"call") FUN(d = d, x = 666, z = 777, y = 999) $df2 [1] 1 2 3 attr(,"call") FUN(d = d, x = 666, z = 777, y = 999)
期望输出
> lapply(list(df1=df1, df2=df2), fn, x=666, z=z.) $df1 [1] TRUE attr(,"call") FUN(d = df1, x = 666, z = 777, y = 999) $df2 [1] TRUE attr(,"call") FUN(d = df2, x = 666, z = 777, y = 999)
注意:寻求基于base R的解决方案。
补充说明
在@MrFlick的回答后,补充说明:实际我有一个大型列表lst,尝试以下代码时出现错误:
> lst <- list(df1=df1, df2=df2) > lapply(lst, function(x) + do.call("fn", list(as.name(x), x=666, z=z.)) + ) Error in as.vector(x, mode = mode) : 'list' object cannot be coerced to type 'symbol'
内容的提问来源于stack exchange,提问作者jay.sf
相关产品推荐
相关产品推荐

