我正在尝试编写一个函数,该函数将对象的名称(如未计算的符号)用于下游应用程序。下面是一个抓住这个意思的例子:
return_obj_name <- function(obj){
inp <- enquo(obj)
inp_name <- rlang::as_name(inp) # Use the name for something
inp_data <- rlang::eval_tidy(inp) # This line just for completeness, not important here
return(inp_name)
}以下是此函数的标准用例:
test_obj <- 42
return_obj_name(test_obj)
[1] "test_obj"到现在为止还好。但是,我计划在map (或map2)语句中使用我的函数作为匿名函数,这就是问题所在。
test_obj2 <- 44
test_vec <- c(test_obj, test_obj2)
map(test_vec, ~ .x %>% return_obj_name())
[[1]]
[1] "."
[[2]]
[1] "."预期的输出应该是:
[[1]]
[1] "test_obj"
[[2]]
[1] "test_obj2"我想我确实明白发生了什么。该函数接收对初始对象的管道引用,它将是".“。它引用了这一点,并通过设计继续下去。
我想知道是否有一种方法可以在调用map的环境中计算引用,而不是像现在这样在map调用中进行计算。
发布于 2020-08-10 10:10:47
在你运行之后
test_obj2 <- 44
test_vec <- c(test_obj, test_obj2)值test_vec不知道用于创建它的变量的名称。它所知道的就是它是一个包含42和44的数值向量。跟踪每个变量的源会产生大量开销。
重要的是要记住,值在R中没有名称;它是有值的名称。它也不总是独一无二的。多个名称可以指向同一个值。
此外,管道运算符不保留变量名。观察
test_obj %>% return_obj_name()
# [1] "."如果希望跟踪值源的标签,则应该使用命名列表(但请记住,它是跟踪名称的集合,集合中的元素不知道它们是否被命名),或者使用单独的名称向量。@Ronak给出的答案提供了一些使用这种策略的很好的选择。
另一种选择是将您的值存储为quosures的集合。例如
test_vec <- quos(test_obj, test_obj2)
map(test_vec, ~return_obj_name(!!.x))但在这里,test_vec存储的是这些变量的名称,而不是它们的值。您需要对其求值以获得值42和44。
发布于 2020-08-10 07:58:17
您已共享的独立示例与map的预期输出不匹配。在独立示例中,您将运行return_obj_name(test_obj)并以"test_obj"的形式获得输出。注意,这里"test_obj"的值是42。但是在map示例中,您的预期输出是返回"42"和"44",而不是test_obj和test_obj2?这其中之一需要改变,才能使问题保持一致。
无论如何,就答案而言,我认为你应该显式地命名你的向量/列表,并将其作为单独的对象传递。
return_obj_name <- function(obj, name){
#Do something
#Do something
return(name)
}例如,使用tibble::lst可以轻松地命名对象。
test_vec <- tibble::lst(test_obj, test_obj2)然后,您可以使用imap:
purrr::imap(test_vec, return_obj_name)
#$test_obj
#[1] "test_obj"
#$test_obj2
#[1] "test_obj2"或基R中的Map:
Map(return_obj_name, test_vec, names(test_vec))如果你想返回"42"和"44",也就是这里的值,那就是return_obj_name函数中的obj值。
https://stackoverflow.com/questions/63331818
复制相似问题