R Pipe Operator
The pipe operator passes the output of one expression as the input to the next. It eliminates deeply nested function calls and makes multi-step transformations read in a natural, left-to-right sequence — the same order you think through the steps.
The Problem Pipes Solve
# Without pipe — deeply nested, read inside-out: result <- round(mean(sqrt(abs(c(-4, 9, -16, 25, -1)))), 2) # With native pipe |> — reads left to right: result <- c(-4, 9, -16, 25, -1) |> abs() |> sqrt() |> mean() |> round(2) # Step by step: # c(-4,9,-16,25,-1) → abs → sqrt → mean → round # [4,9,16,25,1] → [2,3,4,5,1] → 3 → 3
Two Pipe Operators in R
Pipe Package Available Since Notes ────────────────────────────────────────────────────────────── |> Base R R 4.1.0 (2021) No package needed %>% magrittr/dplyr Always More features
Native Pipe |> (R 4.1+)
library(dplyr) c(1, 4, 9, 16, 25) |> sqrt() |> sum() # 15 # With data frames employees |> filter(dept == "IT") |> arrange(desc(salary)) |> select(name, salary)
Magrittr Pipe %>%
library(magrittr) # or just load dplyr c(1, 4, 9, 16, 25) %>% sqrt() %>% sum() # 15
Placeholder in Pipe Chains
# Native pipe placeholder: _ (R 4.2+)
mtcars |> lm(mpg ~ wt, data=_) |> summary()
# Magrittr placeholder: .
c(1,2,3) %>% paste("item", .)
# "item 1" "item 2" "item 3"
Real Analysis Pipeline
raw_sales <- data.frame(
date = c("2024-01-15","2024-01-20","2024-02-10","2024-02-25","2024-03-05"),
region = c("North","South","North","South","North"),
product = c("A","B","A","A","B"),
revenue = c(1200, NA, 1500, 1100, 800)
)
summary_report <- raw_sales |>
filter(!is.na(revenue)) |> # remove NAs
mutate(date = as.Date(date),
month = format(date, "%B")) |> # extract month
group_by(region, month) |>
summarise(total_revenue = sum(revenue),
avg_revenue = mean(revenue),
orders = n(),
.groups = "drop") |>
arrange(region, desc(total_revenue))
print(summary_report)
Pipe vs Step-by-Step Assignment
# Without pipe (intermediate objects pollute environment): step1 <- filter(raw_sales, !is.na(revenue)) step2 <- mutate(step1, month = format(as.Date(date), "%B")) step3 <- group_by(step2, region, month) result <- summarise(step3, total=sum(revenue), .groups="drop") # With pipe (clean, no intermediate variables): result <- raw_sales |> filter(!is.na(revenue)) |> mutate(month = format(as.Date(date), "%B")) |> group_by(region, month) |> summarise(total=sum(revenue), .groups="drop")
Enable |> in RStudio
Go to Tools → Global Options → Code → Editing and check "Use native pipe operator |>". Now the Ctrl+Shift+M shortcut inserts |> instead of %>%.
The pipe operator does not add new functionality — it just changes how code is written. The difference it makes to readability is enormous. Every modern R workflow uses pipes to chain data operations into clear, readable pipelines that a new reader can understand almost immediately.
