准引用和ifelse:取消引用无法按预期方式解析

时间:2019-02-27 17:56:57

标签: r rlang

我期望我可以使用rlang包中的准引用机制,例如!!quo_name()来在mutate()ifelse()中用程序将名称取消引用功能。但是,它没有按我预期的那样工作,如下所示。它没有解析ifelse()调用内mutate()内数据框范围内的名称值,而是仅解析参数的字符值。我能够使用基本功能get()来完成我想要的事情。但是,我一定会感到困惑,并且正在寻找如何在Rlang /准引用世界中做到这一点。说明和帮助表示赞赏。

suppressPackageStartupMessages(library(tidyverse))

df <- tibble(x=c(1, NA_integer_, 3), y=101:103)
print(df)
#> # A tibble: 3 x 2
#>       x     y
#>   <dbl> <int>
#> 1     1   101
#> 2    NA   102
#> 3     3   103

# Expected behavior
df %>%
    mutate(z = ifelse(is.na(x), y, x))
#> # A tibble: 3 x 3
#>       x     y     z
#>   <dbl> <int> <dbl>
#> 1     1   101     1
#> 2    NA   102   102
#> 3     3   103     3

# Similar question seemed to be posted here:
# From: https://community.rstudio.com/t/trouble-with-creating-column-names-from-a-passed-argument-in-function/7819/3
# I expect same output as above, but instead, the column `x` gets filled with the name of the column, not appropriate value.
v_colname <- "x"
df %>%
    mutate(z := ifelse(is.na(!!v_colname), y, !!v_colname)) %>%
    print()
#> # A tibble: 3 x 3
#>       x     y z    
#>   <dbl> <int> <chr>
#> 1     1   101 x    
#> 2    NA   102 x    
#> 3     3   103 x

# Tried variant with `quo_name()`, same unexpected result:
df %>%
    mutate(z := ifelse(is.na(!!quo_name(v_colname)), y, !!quo_name(v_colname)))
#> # A tibble: 3 x 3
#>       x     y z    
#>   <dbl> <int> <chr>
#> 1     1   101 x    
#> 2    NA   102 x    
#> 3     3   103 x

# This works, but I assume I am missing something with quasiquotation semantics:
df %>%
    mutate(z := ifelse(is.na(get(v_colname)), y, get(v_colname)))
#> # A tibble: 3 x 3
#>       x     y     z
#>   <dbl> <int> <dbl>
#> 1     1   101     1
#> 2    NA   102   102
#> 3     3   103     3

# Session info
sessionInfo()
#> R version 3.5.2 (2018-12-20)
#> Platform: x86_64-w64-mingw32/x64 (64-bit)
#> Running under: Windows 10 x64 (build 16299)
#> 
#> Matrix products: default
#> 
#> locale:
#> [1] LC_COLLATE=English_United States.1252 
#> [2] LC_CTYPE=English_United States.1252   
#> [3] LC_MONETARY=English_United States.1252
#> [4] LC_NUMERIC=C                          
#> [5] LC_TIME=English_United States.1252    
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#>  [1] bindrcpp_0.2.2  forcats_0.3.0   stringr_1.3.1   dplyr_0.7.8    
#>  [5] purrr_0.2.5     readr_1.3.1     tidyr_0.8.2     tibble_2.0.1   
#>  [9] ggplot2_3.1.0   tidyverse_1.2.1
#> 
#> loaded via a namespace (and not attached):
#>  [1] Rcpp_1.0.0       cellranger_1.1.0 plyr_1.8.4       pillar_1.3.1    
#>  [5] compiler_3.5.2   highr_0.7        bindr_0.1.1      tools_3.5.2     
#>  [9] digest_0.6.18    lubridate_1.7.4  jsonlite_1.6     evaluate_0.12   
#> [13] nlme_3.1-137     gtable_0.2.0     lattice_0.20-38  pkgconfig_2.0.2 
#> [17] rlang_0.3.1      cli_1.0.1        yaml_2.2.0       haven_2.0.0     
#> [21] xfun_0.4         withr_2.1.2      xml2_1.2.0       httr_1.4.0      
#> [25] knitr_1.21       hms_0.4.2        generics_0.0.2   grid_3.5.2      
#> [29] tidyselect_0.2.5 glue_1.3.0       R6_2.3.0         fansi_0.4.0     
#> [33] readxl_1.2.0     rmarkdown_1.11   modelr_0.1.2     magrittr_1.5    
#> [37] backports_1.1.3  scales_1.0.0     htmltools_0.3.6  rvest_0.3.2     
#> [41] assertthat_0.2.0 colorspace_1.4-0 utf8_1.1.4       stringi_1.2.4   
#> [45] lazyeval_0.2.1   munsell_0.5.0    broom_0.5.1      crayon_1.3.4

reprex package(v0.2.1)于2019-02-27创建

1 个答案:

答案 0 :(得分:1)

我们可以转换为符号(sym),然后求值(!!

library(dplyr)
df %>%
  mutate(z := ifelse(is.na(!!rlang::sym(v_colname)), y, !! rlang::sym(v_colname)))
# A tibble: 3 x 3
#      x     y     z
#  <dbl> <int> <dbl>
#1     1   101     1
#2    NA   102   102
#3     3   103     3