How to Work with Arrays in Ruby

· 6 min read · Updated March 12, 2026 · beginner
ruby arrays guide

Arrays are one of the most frequently used data structures in Ruby. This cookbook provides practical recipes for common array operations.

Creating Arrays

From Scratch

Create an array with literal syntax:

numbers = [1, 2, 3, 4, 5]
words = ["apple", "banana", "cherry"]
mixed = [1, "two", 3.0, nil]

With Array.new

Use Array.new when you need a specific size or default values:

# Create array with 5 nil elements
empty = Array.new(5)
# => [nil, nil, nil, nil, nil]

# Create array with 5 elements set to 0
zeros = Array.new(5, 0)
# => [0, 0, 0, 0, 0]

# Create array with block (each element computed)
squares = Array.new(5) { |i| i ** 2 }
# => [0, 1, 4, 9, 16]

The block form is preferred when each element needs a unique value, because the single-value form can cause issues with mutable objects.

From Other Objects

Convert ranges, strings, and other objects to arrays:

# Range to array
(1..10).to_a
# => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# String to array of characters
"hello".chars
# => ["h", "e", "l", "l", "o"]

# String to array of words
"hello world".split
# => ["hello", "world"]

# CSV or delimited string
"a,b,c".split(",")
# => ["a", "b", "c"]

Adding and Removing Elements

Adding Elements

# Append to end
array = [1, 2, 3]
array << 4
array.push(5, 6)
# => [1, 2, 3, 4, 5, 6]

# Prepend to beginning
array.unshift(0)
# => [0, 1, 2, 3, 4, 5, 6]

# Insert at specific index
array.insert(2, "two")
# => [0, 1, "two", 2, 3, 4, 5, 6]

Removing Elements

array = [1, 2, 3, 4, 5]

# Remove and return last element
last = array.pop
# last = 5, array = [1, 2, 3, 4]

# Remove and return first element
first = array.shift
# first = 1, array = [2, 3, 4]

# Remove element at specific index
array.delete_at(1)
# array = [2, 4]

# Remove all elements that match
array = [1, 2, 3, 2, 4]
array.delete(2)
# array = [1, 3, 4]

Searching and Filtering

Finding Elements

fruits = ["apple", "banana", "cherry", "date"]

# Find first match
fruits.find { |f| f.length > 5 }
# => "banana"

# Find index of first match
fruits.index { |f| f.start_with?("c") }
# => 2

# Check if any element matches
fruits.any? { |f| f.start_with?("b") }
# => true

# Check if all elements match
fruits.all? { |f| f.length < 10 }
# => true

Filtering Arrays

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Select elements matching condition
evens = numbers.select { |n| n.even? }
# => [2, 4, 6, 8, 10]

# Reject elements matching condition
odds = numbers.reject { |n| n.even? }
# => [1, 3, 5, 7, 9]

# Partition into matching/non-matching
evens, odds = numbers.partition { |n| n.even? }
# evens = [2, 4, 6, 8, 10], odds = [1, 3, 5, 7, 9]

Transforming Arrays

Map and Friends

numbers = [1, 2, 3, 4, 5]

# Transform each element
squared = numbers.map { |n| n ** 2 }
# => [1, 4, 9, 16, 25]

# Transform and flatten (for nested results)
nested = numbers.flat_map { |n| [n, n * 2] }
# => [1, 2, 2, 4, 3, 6, 4, 8, 5, 10]

# Collect is alias for map
doubled = numbers.collect { |n| n * 2 }
# => [2, 4, 6, 8, 10]

Chaining Transformations

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Chain filter, transform, and limit
result = numbers
  .select { |n| n > 3 }
  .map { |n| n ** 2 }
  .take(3)
# => [16, 25, 36]

Sorting Arrays

Basic Sorting

numbers = [3, 1, 4, 1, 5, 9, 2, 6]

# Sort ascending
numbers.sort
# => [1, 1, 2, 3, 4, 5, 6, 9]

# Sort descending
numbers.sort.reverse
# => [9, 6, 5, 4, 3, 2, 1, 1]

# Sort with block
numbers.sort { |a, b| b <=> a }
# => [9, 6, 5, 4, 3, 2, 1, 1]

Custom Object Sorting

users = [
  { name: "Alice", age: 30 },
  { name: "Bob", age: 25 },
  { name: "Charlie", age: 35 }
]

# Sort by age
users.sort_by { |u| u[:age] }
# => [{:name=>"Bob", :age=>25}, {:name=>"Alice", :age=>30}, {:name=>"Charlie", :age=>35}]

# Sort by name length
users.sort_by { |u| u[:name].length }
# => [{:name=>"Bob", :age=>25}, {:name=>"Alice", :age=>30}, {:name=>"Charlie", :age=>35}]

Iterating Efficiently

Each Variations

fruits = ["apple", "banana", "cherry"]

# Each with index
fruits.each_with_index { |fruit, i| puts "#{i}: #{fruit}" }

# Each with object
fruits.each_with_object("") { |fruit, str| str << fruit[0] }
# => "abc"

# Cycle (repeat infinitely)
fruits.cycle(2) { |f| puts f }
# prints: apple, banana, cherry, apple, banana, cherry

Reducing to Single Value

numbers = [1, 2, 3, 4, 5]

# Sum all elements
numbers.sum
# => 15

# With initial value
numbers.sum(10)
# => 25

# Custom reduction
product = numbers.reduce(1) { |acc, n| acc * n }
# => 120

# Inject is alias for reduce
sum = numbers.inject(:+)
# => 15

Array Comparisons

Checking Equality

a = [1, 2, 3]
b = [1, 2, 3]
c = [1, 2, 4]

a == b  # => true
a == c  # => false

# Compare arrays element-by-element
a.zip(c).each { |x, y| puts "#{x} vs #{y}" }

Set Operations

a = [1, 2, 3, 4]
b = [3, 4, 5, 6]

# Intersection (common elements)
a & b
# => [3, 4]

# Union (all unique elements)
a | b
# => [1, 2, 3, 4, 5, 6]

# Difference
a - b
# => [1, 2]

b - a
# => [5, 6]

Common Pitfalls

Mutating During Iteration

Never modify the same array you’re iterating over:

# WRONG - unpredictable behavior
numbers = [1, 2, 3]
numbers.each { |n| numbers.delete(n) if n.odd? }
# => [2]

# CORRECT - work on a copy
numbers = [1, 2, 3]
numbers.dup.each { |n| numbers.delete(n) if n.odd? }
# => [2]

Reference vs Copy

Remember that assignment copies references, not objects:

# WRONG - both point to same array
original = [1, 2, 3]
copy = original
copy << 4
original  # => [1, 2, 3, 4] - original modified!

# CORRECT - create a new array
original = [1, 2, 3]
copy = original.dup
# or: copy = original.clone
copy << 4
original  # => [1, 2, 3]

Performance with Large Arrays

For large datasets, consider these tips:

# Use lazy for chainable enumerators
result = (1..1_000_000)
  .lazy
  .select { |n| n.even? }
  .map { |n| n ** 2 }
  .first(10)

# Avoid creating intermediate arrays with blocks
# Prefer:
array.select(&:positive?)
# Over:
array.select { |n| n.positive? }

See Also