与管道运算符和 [ 选择器一起使用时,为什么 colnames 函数会生成小标题而不是矢量?

问题描述

问题:当 colnames 函数与管道运算符 %>%[ 选择器一起使用时,为什么会生成标题

示例:给定以下小标题

library(tidyverse)

x <- tribble(
  ~a,~b,1,1
)

问题:当与管道运算符和 [ 选择器一起使用时,colnames 函数生成一个 tibbe:

x %>% colnames(.)[1]
#> # A tibble: 2 x 1
#>       a
#>   <dbl>
#> 1    NA
#> 2    NA

而我希望它生成一个向量,就好像没有使用管道运算符一样:

colnames(x)[1]
#> [1] "a"

解决方法

管道将左侧插入到右侧 main 函数的第一个参数中,在本例中为 [ 。那就是这三个是一样的:

x %>% colnames(.)[1]

x %>% `[`(colnames(.),1)

x %>% `[`(.,colnames(.),1)

最后一个是相同的,因为如果主函数的参数之一是点,它不会插入左侧。

要防止它插入点,请使用 {...}

x %>% { colnames(.)[1] }

或使用:

x %>% colnames %>% .[1]

或使用 dplyr::first 或 dplyr::slice_head(n = 1) 或 dplyr::nth(1) 或 purrr::pull(1)magrittr::extract(1)head(1)

x %>% colnames %>% first
,

因为 %>% 自动插入 . 作为右侧的第一个参数,除非 . 已经用作右侧的顶级参数-手边

您的右手边是 colnames(.)[1] — 而 . 不是此处的顶级参数。实际上,表达式 colnames(.)[1] 完全等同于

`[`(colnames(.),1)

所以这个表达式的顶级参数是colnames(.)1. 也不是。所以 %>% 将您的表达式转换为

`[`(x,colnames(x),1)

再次等价于

x[colnames(x),1]

这种表达实际上没有意义,并且恰好导致了您所观察到的。

为避免 . 自动插入,您可以将表达式包装到 {…} 中,如 akrun 所示。或者您可以将复合表达式拆分为其组成部分:

x %>% colnames() %>% `[`(1L)
,

我们可以在 first 之后使用 colnames

x %>% 
   colnames %>% 
   first
#[1] "a"

或者在 {} 内阻塞整个表达式以作为单个表达式求值并避免运算符的优先级

x %>%
    {colnames(.)[1]}
#[1] "a"