首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Tidy eval:对map中函数的quosure求值

Tidy eval:对map中函数的quosure求值
EN

Stack Overflow用户
提问于 2020-08-10 06:11:46
回答 2查看 73关注 0票数 2

我正在尝试编写一个函数,该函数将对象的名称(如未计算的符号)用于下游应用程序。下面是一个抓住这个意思的例子:

代码语言:javascript
复制
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)
}

以下是此函数的标准用例:

代码语言:javascript
复制
test_obj <- 42
return_obj_name(test_obj)

[1] "test_obj"

到现在为止还好。但是,我计划在map (或map2)语句中使用我的函数作为匿名函数,这就是问题所在。

代码语言:javascript
复制
test_obj2 <- 44
test_vec <- c(test_obj, test_obj2)
map(test_vec, ~ .x %>% return_obj_name())

[[1]]
[1] "."

[[2]]
[1] "."

预期的输出应该是:

代码语言:javascript
复制
[[1]]
[1] "test_obj"

[[2]]
[1] "test_obj2"

我想我确实明白发生了什么。该函数接收对初始对象的管道引用,它将是".“。它引用了这一点,并通过设计继续下去。

我想知道是否有一种方法可以在调用map的环境中计算引用,而不是像现在这样在map调用中进行计算。

EN

回答 2

Stack Overflow用户

发布于 2020-08-10 10:10:47

在你运行之后

代码语言:javascript
复制
test_obj2 <- 44
test_vec <- c(test_obj, test_obj2)

test_vec不知道用于创建它的变量的名称。它所知道的就是它是一个包含42和44的数值向量。跟踪每个变量的源会产生大量开销。

重要的是要记住,值在R中没有名称;它是有值的名称。它也不总是独一无二的。多个名称可以指向同一个值。

此外,管道运算符不保留变量名。观察

代码语言:javascript
复制
test_obj %>% return_obj_name()
# [1] "."

如果希望跟踪值源的标签,则应该使用命名列表(但请记住,它是跟踪名称的集合,集合中的元素不知道它们是否被命名),或者使用单独的名称向量。@Ronak给出的答案提供了一些使用这种策略的很好的选择。

另一种选择是将您的值存储为quosures的集合。例如

代码语言:javascript
复制
test_vec <- quos(test_obj, test_obj2)
map(test_vec, ~return_obj_name(!!.x))

但在这里,test_vec存储的是这些变量的名称,而不是它们的值。您需要对其求值以获得值42和44。

票数 3
EN

Stack Overflow用户

发布于 2020-08-10 07:58:17

您已共享的独立示例与map的预期输出不匹配。在独立示例中,您将运行return_obj_name(test_obj)并以"test_obj"的形式获得输出。注意,这里"test_obj"的值是42。但是在map示例中,您的预期输出是返回"42""44",而不是test_objtest_obj2?这其中之一需要改变,才能使问题保持一致。

无论如何,就答案而言,我认为你应该显式地命名你的向量/列表,并将其作为单独的对象传递。

代码语言:javascript
复制
return_obj_name <- function(obj, name){
   #Do something
   #Do something
   return(name)
}

例如,使用tibble::lst可以轻松地命名对象。

代码语言:javascript
复制
test_vec <- tibble::lst(test_obj, test_obj2)

然后,您可以使用imap

代码语言:javascript
复制
purrr::imap(test_vec, return_obj_name)
#$test_obj
#[1] "test_obj"

#$test_obj2
#[1] "test_obj2"

或基R中的Map

代码语言:javascript
复制
Map(return_obj_name, test_vec, names(test_vec))

如果你想返回"42""44",也就是这里的值,那就是return_obj_name函数中的obj值。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63331818

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档