【问题标题】:Tidy eval: Evaluation of quosure in function within map整洁的评估:地图内功能的评估
【发布时间】:2020-11-29 13:31:20
【问题描述】:

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

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"

我想我确实了解正在发生的事情。该函数接收对初始对象的管道引用,该对象将是“.”。它用 enquo 引用了这一点,并按设计继续。

我想知道是否有一种方法可以在调用 map 的环境中评估引用,而不是在 map 调用中,就像现在发生的那样。

【问题讨论】:

  • 你为什么需要这个?目的是什么?如果您对这些名称感兴趣,请查看imap
  • “我为什么需要它?”是什么意思?问题还不够吗?我不想要名字,我想要经过解析的带引号的符号。
  • 问题是 42 和 44 不是名称而是值。例如,如果你有数据框怎么办?您希望整个数据框成为 NAME 吗?
  • 42 和 44 的预期输出令人困惑 - 如果您对这些值感兴趣,我相信您的 inp_data 行会返回。如果您对 test_objtest_obj2 感兴趣,我不确定它们是否可以恢复 - 我不相信 test_vec 在构造此示例时仍会知道它的起源。
  • magrittr 管道通过数据屏蔽. 并将该值传递给管道函数来工作。如果您化解管道参数,则完全可以看到.

标签: r tidyverse tidyeval


【解决方案1】:

您共享的独立示例与 map 的预期输出不匹配。在独立示例中,您运行return_obj_name(test_obj) 并得到"test_obj" 的输出。请注意,这里"test_obj" 的值是42。但是在map 示例中,您的预期输出是返回"42""44" 而不是test_objtest_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"

Map 在基础 R 中:

Map(return_obj_name, test_vec, names(test_vec))

如果您想返回 "42""44",即此处的值将是 obj 函数中的 return_obj_name 值。

【讨论】:

    【解决方案2】:

    运行后

    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。

    【讨论】:

      猜你喜欢
      • 2018-06-10
      • 2020-04-28
      • 2015-02-27
      • 1970-01-01
      • 2017-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-08
      相关资源
      最近更新 更多