R - Vectors - Create, Access, Modify
Atomic vectors store elements of a single type. Use `c()` to combine values or type-specific constructors for empty vectors.
Key Insights
- Vectors are R’s fundamental data structure—atomic vectors hold single data types while lists hold mixed types, understanding this distinction prevents type coercion bugs
- R uses 1-based indexing with powerful subsetting via positive integers, negative integers, logical vectors, and names—mastering these four methods enables efficient data manipulation
- Vector operations are vectorized by default with automatic recycling of shorter vectors, but recycling can silently introduce errors when vector lengths aren’t multiples
Creating Atomic Vectors
Atomic vectors store elements of a single type. Use c() to combine values or type-specific constructors for empty vectors.
# Numeric vectors
nums <- c(1, 2, 3, 4, 5)
decimals <- c(1.5, 2.7, 3.9)
# Character vectors
chars <- c("apple", "banana", "cherry")
# Logical vectors
bools <- c(TRUE, FALSE, TRUE, TRUE)
# Integer vectors (note the L suffix)
ints <- c(1L, 2L, 3L, 4L)
# Empty vectors with type
numeric(5) # [1] 0 0 0 0 0
character(3) # [1] "" "" ""
logical(4) # [1] FALSE FALSE FALSE FALSE
Sequences and repetitions provide shortcuts for common patterns:
# Sequences
seq1 <- 1:10
seq2 <- seq(from = 0, to = 100, by = 10)
seq3 <- seq(0, 1, length.out = 11)
# Repetitions
rep1 <- rep(5, times = 3) # [1] 5 5 5
rep2 <- rep(c(1, 2), times = 3) # [1] 1 2 1 2 1 2
rep3 <- rep(c(1, 2), each = 3) # [1] 1 1 1 2 2 2
rep4 <- rep(c(1, 2), length.out = 7) # [1] 1 2 1 2 1 2 1
Type coercion occurs automatically when mixing types, following the hierarchy: logical < integer < numeric < character.
mixed <- c(TRUE, 2L, 3.5, "text")
typeof(mixed) # "character"
mixed # [1] "TRUE" "2" "3.5" "text"
# Explicit coercion
as.numeric(c("1", "2", "3")) # [1] 1 2 3
as.character(c(1, 2, 3)) # [1] "1" "2" "3"
as.logical(c(0, 1, 2)) # [1] FALSE TRUE TRUE
Creating Lists
Lists are recursive vectors that can hold any type, including other lists.
# Basic list creation
list1 <- list(1, "text", TRUE, c(1, 2, 3))
# Named lists
person <- list(
name = "John",
age = 30,
scores = c(85, 90, 92),
active = TRUE
)
# Nested lists
nested <- list(
data = list(
x = 1:5,
y = 6:10
),
metadata = list(
created = "2024-01-01",
version = 1.0
)
)
# Convert vector to list
vec <- c(a = 1, b = 2, c = 3)
as.list(vec)
Accessing Vector Elements
R provides four subsetting methods, each with distinct use cases.
Positive Integer Indexing
x <- c(10, 20, 30, 40, 50)
# Single element (1-based)
x[1] # [1] 10
x[5] # [1] 50
# Multiple elements
x[c(1, 3, 5)] # [1] 10 30 50
x[c(1, 1, 2)] # [1] 10 10 20 (duplicates allowed)
# Sequences
x[2:4] # [1] 20 30 40
Negative Integer Indexing
Negative indices exclude elements:
x <- c(10, 20, 30, 40, 50)
x[-1] # [1] 20 30 40 50
x[-c(1, 5)] # [1] 20 30 40
x[-(2:4)] # [1] 10 50
# Cannot mix positive and negative
# x[c(1, -2)] # Error
Logical Indexing
Logical vectors select elements where TRUE:
x <- c(10, 20, 30, 40, 50)
# Explicit logical vector
x[c(TRUE, FALSE, TRUE, FALSE, TRUE)] # [1] 10 30 50
# Conditional selection
x[x > 25] # [1] 30 40 50
x[x %% 20 == 0] # [1] 20 40
# Multiple conditions
x[x > 15 & x < 45] # [1] 20 30 40
# Recycling with logical vectors
x[c(TRUE, FALSE)] # [1] 10 30 50 (recycled to match length)
Named Indexing
Access elements by name when vectors have a names attribute:
scores <- c(math = 85, science = 90, english = 88)
scores["math"] # math: 85
scores[c("science", "math")] # science: 90, math: 85
# Check and set names
names(scores) # [1] "math" "science" "english"
names(scores) <- c("m", "s", "e")
Accessing List Elements
Lists require different subsetting operators based on desired output:
person <- list(
name = "John",
age = 30,
scores = c(85, 90, 92)
)
# Single bracket returns a list
person[1] # List with one element
person["name"] # List with one element
class(person[1]) # "list"
# Double bracket returns the element itself
person[[1]] # [1] "John"
person[["name"]] # [1] "John"
class(person[[1]]) # "character"
# Dollar sign for named elements
person$name # [1] "John"
person$scores[2] # [1] 90
# Multiple elements (only with single bracket)
person[c("name", "age")]
person[c(1, 3)]
Modifying Vectors
Replacement
x <- c(10, 20, 30, 40, 50)
# Single element
x[3] <- 35
x # [1] 10 20 35 40 50
# Multiple elements
x[c(1, 5)] <- c(15, 55)
x # [1] 15 20 35 40 55
# Conditional replacement
x[x > 40] <- 100
x # [1] 15 20 35 100 100
# Replacement with recycling
x[2:4] <- 0
x # [1] 15 0 0 0 100
Adding Elements
x <- c(1, 2, 3)
# Append to end
x <- c(x, 4, 5)
x # [1] 1 2 3 4 5
# Insert at beginning
x <- c(0, x)
x # [1] 0 1 2 3 4 5
# Insert in middle
x <- c(x[1:3], 99, x[4:length(x)])
x # [1] 0 1 2 99 3 4 5
# Using append()
x <- append(x, 100, after = 3)
Removing Elements
x <- c(10, 20, 30, 40, 50)
# Remove by index
x <- x[-3]
x # [1] 10 20 40 50
# Remove multiple
x <- x[-c(1, 3)]
x # [1] 20 50
# Remove by condition
x <- c(10, 20, 30, 40, 50)
x <- x[x <= 40]
x # [1] 10 20 30 40
Modifying Lists
person <- list(name = "John", age = 30)
# Modify existing elements
person$age <- 31
person[["name"]] <- "Jane"
# Add new elements
person$email <- "jane@example.com"
person[["phone"]] <- "555-0100"
# Remove elements (assign NULL)
person$phone <- NULL
# Replace multiple elements
person[c("name", "age")] <- list("Bob", 25)
Vector Operations and Recycling
R vectorizes operations and recycles shorter vectors:
# Element-wise operations
x <- c(1, 2, 3, 4)
y <- c(10, 20, 30, 40)
x + y # [1] 11 22 33 44
x * 2 # [1] 2 4 6 8
# Recycling with equal multiples
x <- c(1, 2, 3, 4, 5, 6)
y <- c(10, 20)
x + y # [1] 11 22 13 24 15 26
# Warning when not equal multiples
x <- c(1, 2, 3, 4, 5)
y <- c(10, 20)
x + y # Warning: longer object length is not a multiple of shorter
# [1] 11 22 13 24 15
Vectorized operations with comparison and logical operators:
x <- c(1, 2, 3, 4, 5)
# Comparisons return logical vectors
x > 3 # [1] FALSE FALSE FALSE TRUE TRUE
x %in% c(2, 4, 6) # [1] FALSE TRUE FALSE TRUE FALSE
# Logical operations
(x > 2) & (x < 5) # [1] FALSE FALSE TRUE TRUE FALSE
(x < 2) | (x > 4) # [1] TRUE FALSE FALSE FALSE TRUE
Understanding vector creation, access patterns, and modification operations forms the foundation for effective R programming. These operations extend to matrices, data frames, and other structures built on vectors.