Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
library(bench)
library(data.table)
library(tidyverse)

df_df <- data.frame(x = rnorm(10^5))

df_tbl <- as_tibble(df_df)

df_dt <- as.data.table(df_df)

r_pipe <- function(df) {
  df ->.;
    .[x < 0, ] ->.;
  `+`(., 100)
}

dplyr_pipe <- function(df) {
  df %>%
    filter(x < 0) %>%
    mutate(x = x + 100)
}

dt_pipe <- function(df) {
  df[x < 0, ][
    x + 100]
}

mark(base = r_pipe(df_df),
  dplyr = dplyr_pipe(df_tbl),
  data.table = dt_pipe(df_dt),
  iterations = 1000,
  check = FALSE) %>%
  arrange(median) %>%
  select(-result:-gc)
  
  # A tibble: 3 x 9
  expression      min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
  <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
1 base        595.2us  651.1us     1498. 1013.08KB    0      1000     0   667.45ms
2 dplyr        1.36ms   1.66ms      562.    2.32MB    0.562   999     1      1.78s
3 data.table   4.32ms   5.59ms      163.    2.53MB    1.81    989    11      6.08s

Goofing around a bit more with R’s native “pipe”. Note that this is just for fun and using this syntax is strongly discouraged as it is difficult to understand. That said, a base R pipe, akin to the {magrittr} pipe is coming.

Code Block
languager
#Using R's native pipe operator

#Inspiration:
#https://win-vector.com/2017/07/07/in-praise-of-syntactic-sugar/
#The native pipe: `->.;`

#Basic example, using the typical assignment direction.
# Note the need to create a child environment with `{}` to get this to work.
# Also note the need to explicitly use dot notation to signify a resulting
# object.
result_v1 <- {
  0 ->.; #The native "pipe"
  cos(.)
}
result_v1
#> [1] 1

#Another example without a child environment, but requires assignment at the
# bottom of the code.
0 ->.;
  cos(.) -> result_1_v2
result_v2
#> Error in eval(expr, envir, enclos): object 'result_v2' not found

#This example expands the use of the pipe to include an infix operator as a
# function, making operators like `+`, `-`, `*` pipe friendly.
result_3a <- {
  0 ->.;
  cos(.) ->.;
  `+`(., 2 * .) #Infix operator
}
result_3a
#> [1] 3

#Here we have pipes inside of pipes with the "dot" having different meanings,
# depending on where it is used. This is because each environment can have its
# own definition of what an object means. Useful when piped operations are
# complex, or you are using lambda/anonymous functions that recycle variable
# names.
result_3b <- {
  0 ->.;
  cos(.) ->.;
  `+`(., { #Child environment inside another environment
    . ->.;
    `*`(., 2)
  }
  )
}
result_3b
#> [1] 3

#Same as above, just proving to myself that the result is behaving as expected.
result_4 <- {
  0 ->.; #The native "pipe"
  cos(.) ->.;
  `+`(., {
    . ->.; #Infix operator
    `*`(., 3)
  }
  )
}
result_4
#> [1] 4