yihui yihui ,你好
看到这个更新,确实觉得不错。
但在官网也没说明。新的管道操作有没有快捷键啊。是不是和{magrittr}一样的?
我认为管道操作一定要有快捷键,这样写起代码来才顺畅

    x <- c(1:10, NA)
    
    a_fun <- function(x) {
      . <- x
      . <- ifelse(is.na(.), 0, .)
      . <- (. + 1) * 3
      . <- sort(.)
      head(., 5)
    }
    
    b_fun <- function(x) {
      x |>
        {\(.) ifelse(is.na(.), 0, .)}() |>
        {\(.) (. + 1) * 3}() |>
        sort() |> 
        head(5)
    }
    
    a_fun(x)
    #> [1]  3  6  9 12 15
    b_fun(x)
    #> [1]  3  6  9 12 15
    
    dput(a_fun)
    #> function (x) 
    #> {
    #>     . <- x
    #>     . <- ifelse(is.na(.), 0, .)
    #>     . <- (. + 1) * 3
    #>     . <- sort(.)
    #>     head(., 5)
    #> }
    dput(b_fun)
    #> function (x) 
    #> {
    #>     head(sort({
    #>         function(.) (. + 1) * 3
    #>     }({
    #>         function(.) ifelse(is.na(.), 0, .)
    #>     }(x))), 5)
    #> }

    <sup>Created on 2021-05-24 by the reprex package (v2.0.0)</sup>

    想了好久,感觉我还是更喜欢传统的写法。也可以在Rstudio设置 ". <- " 快捷键。写出来的代码也可以很简练。如函数a_fun。这本身就符合奥卡姆剃刀原则。这是其一。
    其二, 使用管道符号以后,写出来函数的格式不稳定。比如,dput(b_fun) 以后和原来的代码完全不一样。虽然这对大部分用户来说并不是什么问题,但我本人不太喜欢。

    个人观点。

      JackieMe 你不是第一个这么说的人。一堆特殊字符(大括号、反斜杠、小括号、点、竖线、小于号)堆在一起,确实是太 Perl 了。

      所以我还是喜欢 a_fun 里的写法,一步一赋值,简单明了,排错方便。管道的写法太怂恿用户追求形式上的美感,而这种外表美掩盖了潜在的代价。每次看到这种讨论,总让我联想起古诗与现代诗。形式美是一种美,但特别容易病态和狂热,舍本逐末(比如我认为诗的平仄差不多就行,完全不必成为规则;管道也不必管天管地,不是所有代码都适合管道;管道本是 Unix 的发明,也没见到 Shell 脚本到处都是管道吧,通常也都是普通的 if 判断或 for 循环;我一直都不是很理解为啥 R 社区这么狂热于管道)。

      a_fun 这种一步一赋值的写法最容易被人诟病的是,当变量名比较长时,写起来就很啰嗦了。这里用 . 简写看起来还行。我通常绕过这个问题的办法是写新函数:如果需要重复操作一个变量,那么就把这部分代码抽出去写一个新函数,新函数的参数用短变量名。如:

      c_fun <- function(x) {
        x_squared <- x^2
        x <- (x_squared + 1) * (x_squared -2)
        head(x, 5)
      }

      为了避免重复敲 x_squared 这个长名字,可以新写一个函数,参数用短名:

      d_fun <- function(x) {
        (x + 1) * (x -2)
      }

      然后调用新函数:

      c_fun <- function(x) {
        x <- d_fun(x^2)
        head(x, 5)
      }

      抽离局部代码到新函数这种做法也便于单元测试。不过我这都是从开发者角度说的。数据分析的代码风格会不一样,可能不会频繁抽离新函数。

      我自己刚开始接触管道的时候, 有过什么都想上管道的倾向 ... 现在处于一种混杂的状态. 至于什么时候用什么时候不用, 我的标准是认知上的流畅和简洁. 但这个 "简洁" 并不是完全说输入的代码越少越好. 我下面举一些例子:

      my_data[, c("var_1", "var_2", "var_3")] %>% my_fun()

      上面这个例子我觉得就是一个简单的, 但是显示管道优点的例子. 因为它的形式是贴合你的思维过程的. 如果你用传统的方式来写, 就会有点拗口:

      my_fun(my_data[, c("var_1", "var_2", "var_3")])

      因为 my_fun() 这个操作是后发生的.

      如果用中间的变量, 我个人会觉得有点笨拙:

      new_data <- my_data[, c("var_1", "var_2", "var_3")]
      my_fun(new_data)

      这么写对我个人来说还有三个不爽的点:

      1. new_data 这个变量是不重复使用的, 有点废话.
      2. new_data 会阻断思维过程, 本来一句话能说清楚的, 变得冗长了. 我下次看的时候, 加工时间会更长.
      3. 如果你采用中间变量是为了更清晰, 更显性, 那么这背后需要你花心思去取直观简洁的变量名, 这个过程对我来说很痛苦.

      但就算我支持管道, 我也不会刻意这样写:

      c("var_1", "var_2", "var_3") %>%
        {my_data[, .]} %>%
        my_fun()

      因为我思考的时候, my_data[, c("var_1", "var_2", "var_3")] 是整体出现的. 字面上的, 刻意的简洁反而是损害思维上的简洁的. 除非 c("var_1", "var_2", "var_3")] 是我之前处理的结果.

      这些例子看起来很无足轻重, 但是是我实际开发时的体验的缩影.

      开辟第三战场

      # Example - 1
      1:10 ->.; head(.) # 如果换行分号就可去掉了。
      
      # Example - 2
      1:10 ->.
        head(.)
      
      # Example - 3
      library(dplyr)
      mtcars ->.
        group_by(., cyl) ->.
        summarise(., mpg_avg = mean(mpg)) -> df

        chuxinyuan
        可以设置个 " ->.; "的快捷键。 想换行就换行,不想换行就接着写。哈哈~~

        10:1 |> sort() |> head(5) ->.; ifelse(. < 5, 0, .) ->.; plot(.)

        这样是不是有点梦幻了。

        等同于这样:

            . <- head(sort(10:1), 5)
            . <- ifelse(. < 5, 0, .)
            plot(.)
          5 天 后

          barnett874

          设置了还是... @@“

          x 3.3 GiB [master*]> devtools::session_info()$platform |> 
               unlist() |> 
               data.frame(Category = names(.), session_info = .)
          Error in data.frame(unlist(devtools::session_info()$platform), Category = names(.),  : 
            arguments imply differing number of rows: 9, 0
          
          x 3.3 GiB [master*]> devtools::session_info()$platform %>% 
               unlist() %>% 
               data.frame(Category = names(.), session_info = .)
                   Category                 session_info
          version   version R version 4.1.0 (2021-05-18)
          os             os           Ubuntu 20.04.2 LTS
          system     system            x86_64, linux-gnu
          ui             ui                      RStudio
          language language                           en
          collate   collate                  en_US.UTF-8
          ctype       ctype                  en_US.UTF-8
          tz             tz                   Asia/Tokyo
          date         date                   2021-05-30

          好了~

          3.3 GiB [master*]> devtools::session_info()$platform %>% 
               unlist() %>% 
               (function(df) data.frame(Category = names(df), session_info = df))()
                   Category                 session_info
          version   version R version 4.1.0 (2021-05-18)
          os             os           Ubuntu 20.04.2 LTS
          system     system            x86_64, linux-gnu
          ui             ui                      RStudio
          language language                           en
          collate   collate                  en_US.UTF-8
          ctype       ctype                  en_US.UTF-8
          tz             tz                   Asia/Tokyo
          date         date                   2021-05-30

            ryo 可以用 R-perl 这么写:

            devtools::session_info()$platform |> 
                 unlist() |> 
                 {\(.) data.frame(Category = names(.), session_info = .)}()

            😂

            11 天 后
            1 年 后