Short answer: In R, everything is a vector: c(3, 1, 2) builds one, operations apply element by element, and indexes start at 1. Assign with <-, subset with x[x > 1] or df[df$cpu > 50, ], loop less and use sapply, vapply or Map instead, chain steps with the native pipe |>, and write short functions as \(x) x + 1. Read data with read.csv(), catch errors with tryCatch(), and summarise with summary(), table() and aggregate().
The examples in this R cheat sheet were run with R 4.3.3 on 9 October 2026, using base R only. The current release is R 4.6.1; functions marked 4.4+ or later were checked against the R NEWS file.
Table of Contents
Vectors and basic types
| Syntax | What it does | Example |
|---|---|---|
x <- c(3, 1, 2) | Create a vector (= also assigns) | ports <- c(80, 443) |
5L, "a", TRUE, NA, NULL | Integer, character, logical, missing value, nothing | class(5L) gives "integer" |
1:5, seq(1, 10, by = 3) | Sequences | seq_len(n) is safe when n is 0 |
rep(x, times = 2), rep(x, each = 2) | Repeat | rep(1:2, each = 2) gives 1 1 2 2 |
x * 2, x + y | Element-wise arithmetic; shorter vectors recycle | c(3, 1, 2) * 2 |
%/%, %%, ^ | Integer division, modulo, power | 7 %/% 2 is 3 |
sum, mean, max, range, cumsum | Summaries; na.rm = TRUE skips NA | mean(c(1, NA, 3), na.rm = TRUE) |
sort, order, rev, unique | order returns positions, for sorting other things | df[order(-df$cpu), ] |
%in%, any, all, which | Membership and tests (%notin% is in base from 4.6) | which(x > 1) |
ifelse(test, yes, no) | Vectorised if | ifelse(x > 1, "big", "small") |
is.na(), as.integer(), as.character() | Test and convert | as.numeric("abc") gives NA with a warning |
factor(x, levels = …) | Categorical data with fixed levels | table(f) counts per level |
matrix(1:6, nrow = 2) | Matrix (filled by column); %*% multiplies | m[2, 3] |
Never compare floating-point numbers with ==: 0.1 + 0.2 == 0.3 is FALSE. Use isTRUE(all.equal(a, b)).
Indexing and subsetting
| Syntax | Returns | Example |
|---|---|---|
x[2], x[c(1, 3)] | Elements by position (1-based) | x[length(x)] is the last |
x[-1] | Everything except position 1 | x[-(1:2)] |
x[x > 1] | Elements where a logical test is TRUE | lat[lat > 500] |
v["b"] | By name | v <- c(a = 1, b = 2) |
l[["key"]] vs l["key"] | The element itself vs a one-element list | cfg[["host"]] |
l$key | Shorthand for [["key"]] | df$cpu |
df[rows, cols] | Data frame rows and columns; leave one blank for all | df[df$cpu > 50, c("host", "cpu")] |
head(x, n), tail(x, n) | First or last n | head(df, 3) |
Data frames
| Function | What it does | Example |
|---|---|---|
data.frame() | Build a table from equal-length vectors | data.frame(host = c("web01", "db01"), cpu = c(35, 55)) |
str(df), summary(df) | Structure and per-column summaries | First thing to run on new data |
nrow, ncol, names | Size and column names | names(df) |
df$new <- … | Add or replace a column | df$high <- df$cpu > 60 |
subset(df, cond, select = …) | Filter rows and pick columns | subset(df, cpu > 50, select = c(host, cpu)) |
aggregate(y ~ g, data, FUN) | Group and summarise | aggregate(cpu ~ role, data = df, FUN = mean) |
tapply(x, g, f) | Apply a function per group | with(df, tapply(cpu, role, max)) |
merge(a, b, by = "k") | Join two data frames | merge(df, owners, by = "role") |
rbind, cbind | Stack rows or columns | rbind(df1, df2) |
split(x, g) | List of pieces per group | split(df$cpu, df$role) |
transform(df, …) | Add computed columns | transform(df, cpu_frac = cpu / 100) |
df |> subset(role == "web") |> nrow()
mtcars |> lm(mpg ~ wt, data = _) |> coef() # _ placeholder must be a named argument
Lists, functions and the apply family
| Syntax | What it does | Example |
|---|---|---|
list(host = "web01", ports = c(80, 443)) | Container for mixed types, can nest | l$meta$os |
l$key <- NULL | Remove an element | cfg$password <- NULL |
f <- function(x, y = 2, ...) { … } | Function with default and extra arguments; the last value is returned | greet <- function(name, greeting = "Hello") |
\(x) x + 1 | Short lambda (R 4.1+) | sapply(1:3, \(i) i^2) |
<<- | Assign in an enclosing environment (closures) | n <<- n + 1 |
missing(arg) | Was an argument supplied? | if (missing(b)) "no b" |
match.arg(x, choices) | Validate against allowed values, with partial matching | match.arg("med", c("low", "medium")) |
lapply / sapply | Apply over a list; return a list / simplify | lapply(files, readLines) |
vapply(x, f, integer(1)) | Like sapply, with a checked result type | vapply(c("a", "bb"), nchar, integer(1)) |
Map, mapply | Iterate over several vectors in parallel | Map(\(a, b) a + b, 1:2, 3:4) |
Reduce, Filter | Fold and filter | Filter(\(n) n %% 2 == 0, 1:6) |
apply(m, 1, f) | Rows (1) or columns (2) of a matrix | apply(m, 2, max) |
do.call(f, list) | Call with arguments from a list | do.call(rbind, pieces) |
x %||% y (4.4+) | y when x is NULL | opts$timeout %||% 30 |
Control flow
| Syntax | Example |
|---|---|
if (…) { … } else if (…) { … } else { … } | if (code >= 500) "server" else "ok" |
for (h in hosts) { … } | for (i in seq_along(x)) … |
while (cond) { … }, repeat { … } | repeat needs a break |
next / break | Skip an iteration / leave the loop |
switch(x, a = 1, b = 2, default) | switch("db", web = 80, db = 3306, 0) gives 3306 |
if needs a single TRUE or FALSE. Use ifelse() or any()/all() when the condition is a vector, otherwise R 4.2+ raises an error.
Strings and regular expressions
| Function | What it does | Example |
|---|---|---|
paste(a, b, sep = "-"), paste0() | Join; collapse joins a vector into one string | paste(hosts, collapse = ",") |
sprintf() | printf-style formatting, vectorised | sprintf("%-8s %5d", host, port) |
format(x, big.mark = ",") | Number formatting | format(1234567.891, big.mark = ",", nsmall = 2) |
nchar, toupper, trimws, substr | Length, case, trim, substring | substr(s, 1, 5) |
strsplit(s, ",")[[1]] | Split (returns a list) | strsplit("a,b,c", ",")[[1]] |
startsWith, endsWith | Prefix and suffix tests | endsWith(f, ".log") |
grepl(pat, x) | TRUE/FALSE per element | grepl("^web", hosts) |
grep(pat, x, value = TRUE) | Matching elements (grepv() in 4.5+ does the same) | grep("db", hosts, value = TRUE) |
sub / gsub | Replace first / all; \\1 for groups | sub("^(\\w+)\\..*$", "\\1", fqdn) |
regmatches(x, gregexpr(pat, x)) | Extract all matches | regmatches(s, gregexpr("[0-9]+", s))[[1]] |
fixed = TRUE, perl = TRUE | Literal match / PCRE (lookarounds) | grepl(".", x, fixed = TRUE) |
r"(C:\path)" | Raw string, no escaping (4.0+) | Windows paths, regexes |
R strings need double backslashes in patterns: "\\d+" is the regex \d+. A raw string such as r"(\d+)" avoids that.
Files, dates and running R from the shell
| Task | Code |
|---|---|
| Read a CSV | df <- read.csv("hosts.csv") (stringsAsFactors is FALSE by default since 4.0) |
| Write a CSV | write.csv(df, "out.csv", row.names = FALSE) |
| Lines of text | readLines(path) / writeLines(lines, path) |
| Append | cat("line\n", file = path, append = TRUE) |
| Save any R object | saveRDS(df, "df.rds") then readRDS("df.rds") |
| Files | file.exists, list.files(dir, pattern = "\\.csv$"), unlink(path), tempfile() |
| Environment | Sys.getenv("HOME") |
| Dates | as.Date("2026-10-09") + 30, format(d, "%d %b %Y") |
| Parse a log time | as.POSIXct("09/Oct/2026:10:00:00", format = "%d/%b/%Y:%H:%M:%S", tz = "UTC") |
| Time difference | difftime(t2, t1, units = "mins") |
| Run a command | system2("uptime", stdout = TRUE) |
For server admins: Rscript runs R non-interactively, so it fits in cron jobs and pipelines: Rscript report.R, or one-liners such as Rscript -e 'summary(read.csv("latency.csv")$ms)'. Install the interpreter from the distribution (dnf install R from EPEL on AlmaLinux, apt install r-base on Debian and Ubuntu).
Errors and conditions
res <- tryCatch({
stop("bad port")
}, error = function(e) {
paste("caught:", conditionMessage(e))
}, finally = {
cat("cleanup\n")
})
print(res) # "caught: bad port"
| Function | What it does |
|---|---|
stop(msg), warning(msg), message(msg) | Signal an error, a warning or a message (messages go to stderr) |
tryCatch(expr, error = , warning = , finally = ) | Handle conditions; a caught warning stops the expression |
withCallingHandlers() + invokeRestart("muffleWarning") | Log a warning and carry on |
try(expr, silent = TRUE) | Returns an object of class try-error on failure |
stopifnot("port must be numeric" = is.numeric(p)) | Assertions with custom messages |
on.exit(close(con), add = TRUE) | Cleanup when the function exits |
errorCondition(msg, class = "configError") | Custom condition class to catch by name |
Quick statistics and plots
| Function | What it does | Example |
|---|---|---|
summary(x) | Min, quartiles, mean, max | summary(lat) |
quantile(x, c(0.5, 0.95)) | Percentiles | p50 and p95 latency |
sd, var, median, cor | Spread and correlation | cor(mtcars$mpg, mtcars$wt) |
table(x), prop.table() | Counts and proportions | sort(table(codes), decreasing = TRUE) |
cut(x, breaks) | Bin numbers into ranges | table(cut(lat, c(0, 100, 500, Inf))) |
lm(y ~ x1 + x2, data) | Linear model; coef() and summary() on the result | lm(mpg ~ wt + hp, data = mtcars) |
set.seed(1), sample, rnorm | Reproducible random numbers | sample(1:10, 3) |
hist, plot, boxplot | Base graphics | Wrap with png("out.png") … dev.off() on a headless server |
lat <- c(120, 95, 300, 110, 2000, 130)
quantile(lat, c(0.5, 0.95))
# 50% 95%
# 125 1575
Official documentation (checked 9 October 2026): An Introduction to R · R Language Definition · R NEWS (release notes) · R manuals · The R Project
R Cheat Sheet at a glance


Related guides: Python Cheat Sheet: Syntax, Data Types and File Handling · Excel Cheat Sheet: Formulas, Dynamic Arrays and Shortcuts · SQL Cheat Sheet: MySQL, MariaDB and PostgreSQL Syntax.
Reading a lot of our guides? Go ad-free with srvScripts Pro for $6 a month. It also pays for new guides. Cancel any time.