Skip to content

Ruby Arrays

Arrays are one of the most commonly used data structures in Ruby, used to store ordered collections of elements. Ruby arrays are powerful and flexible, can store elements of different types, and provide rich built-in methods for data manipulation. This chapter will introduce in detail the creation, manipulation, and processing methods of arrays in Ruby.

🎯 Array Basics

Array Definition

Ruby provides multiple ways to create arrays:

ruby
# Use literal syntax
fruits = ["Apple", "Banana", "Orange"]
numbers = [1, 2, 3, 4, 5]
mixed = ["String", 123, true, nil]

# Use Array.new method
empty_array = Array.new
sized_array = Array.new(3)  # [nil, nil, nil]
initialized_array = Array.new(3, "default")  # ["default", "default", "default"]

# Use %w shortcut to create string array
words = %w[hello world ruby programming]
# Equivalent to ["hello", "world", "ruby", "programming"]

# Use %i shortcut to create symbol array
symbols = %i[apple banana orange]
# Equivalent to [:apple, :banana, :orange]

# Use range to create array
range_array = (1..5).to_a  # [1, 2, 3, 4, 5]
range_array2 = ("a".."e").to_a  # ["a", "b", "c", "d", "e"]

# Create array from other objects
array_from_string = "hello".split("")  # ["h", "e", "l", "l", "o"]
array_from_range = Array(1..3)  # [1, 2, 3]

Array Access

ruby
fruits = ["Apple", "Banana", "Orange", "Grape", "Strawberry"]

# Access elements by index
puts fruits[0]    # Apple
puts fruits[2]    # Orange
puts fruits[-1]   # Strawberry (negative index starts from end)
puts fruits[-2]   # Grape

# Access multiple elements by range
puts fruits[1..3].inspect     # ["Banana", "Orange", "Grape"]
puts fruits[1...3].inspect    # ["Banana", "Orange"] (doesn't include end index)
puts fruits[-3..-1].inspect   # ["Orange", "Grape", "Strawberry"]

# Use at method for access
puts fruits.at(1)  # Banana

# Get first and last elements
puts fruits.first  # Apple
puts fruits.last   # Strawberry

# Get first n or last n elements
puts fruits.first(3).inspect  # ["Apple", "Banana", "Orange"]
puts fruits.last(2).inspect   # ["Grape", "Strawberry"]

# Check if array contains an element
puts fruits.include?("Banana")  # true
puts fruits.include?("Watermelon")  # false

📏 Array Properties

Array Length and Size

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

# Get array length
puts numbers.length  # 5
puts numbers.size    # 5 (alias for length)

# Check if array is empty
puts numbers.empty?  # false
puts [].empty?       # true

# Get array count information
puts numbers.count           # 5
puts numbers.count(3)        # 1 (count specific elements)
puts numbers.count { |n| n > 3 }  # 2 (count elements satisfying condition)

Array Comparison

ruby
arr1 = [1, 2, 3]
arr2 = [1, 2, 3]
arr3 = [3, 2, 1]

# Equality comparison
puts arr1 == arr2  # true
puts arr1 == arr3  # false

# Compare array contents (considering order)
puts arr1.eql?(arr2)  # true

# Object identity comparison
puts arr1.equal?(arr2)  # false (different objects)
puts arr1.equal?(arr1)  # true (same object)

# Array comparison (lexicographical)
puts [1, 2, 3] <=> [1, 2, 3]  # 0 (equal)
puts [1, 2, 3] <=> [1, 2, 4]  # -1 (less than)
puts [1, 2, 4] <=> [1, 2, 3]  # 1 (greater than)

➕ Array Operations

Adding Elements

ruby
# Use push or << to add elements at the end
fruits = ["Apple", "Banana"]
fruits.push("Orange")
fruits << "Grape"  # Shorthand form
puts fruits.inspect  # ["Apple", "Banana", "Orange", "Grape"]

# Use unshift to add elements at the beginning
fruits.unshift("Strawberry")
puts fruits.inspect  # ["Strawberry", "Apple", "Banana", "Orange", "Grape"]

# Insert elements at specified position
fruits.insert(2, "Mango", "Pear")
puts fruits.inspect  # ["Strawberry", "Apple", "Mango", "Pear", "Banana", "Orange", "Grape"]

# Use concat to concatenate arrays
more_fruits = ["Cherry", "Peach"]
fruits.concat(more_fruits)
puts fruits.inspect  # ["Strawberry", "Apple", "Mango", "Pear", "Banana", "Orange", "Grape", "Cherry", "Peach"]

Deleting Elements

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

# Delete last element
last_element = numbers.pop
puts last_element   # 10
puts numbers.inspect  # [1, 2, 3, 4, 5, 6, 7, 8, 9]

# Delete first element
first_element = numbers.shift
puts first_element   # 1
puts numbers.inspect  # [2, 3, 4, 5, 6, 7, 8, 9]

# Delete element with specified value
numbers.delete(5)
puts numbers.inspect  # [2, 3, 4, 6, 7, 8, 9]

# Delete element at specified index
deleted_element = numbers.delete_at(0)
puts deleted_element  # 2
puts numbers.inspect  # [3, 4, 6, 7, 8, 9]

# Delete elements satisfying condition
numbers.delete_if { |n| n > 7 }
puts numbers.inspect  # [3, 4, 6, 7]

# Clear array
numbers.clear
puts numbers.inspect  # []

Modifying Elements

ruby
letters = ["a", "b", "c", "d", "e"]

# Modify single element by index
letters[0] = "A"
puts letters.inspect  # ["A", "b", "c", "d", "e"]

# Modify multiple elements by range
letters[1..2] = ["B", "C"]
puts letters.inspect  # ["A", "B", "C", "d", "e"]

# Use fill to fill elements
numbers = [1, 2, 3, 4, 5]
numbers.fill(0, 2, 2)  # Start at index 2, fill 2 elements with 0
puts numbers.inspect   # [1, 2, 0, 0, 5]

# Use fill to fill entire array
empty_array = [nil, nil, nil]
empty_array.fill("default")
puts empty_array.inspect  # ["default", "default", "default"]

🔍 Array Search and Filter

Finding Elements

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

# Find first element satisfying condition
even_number = numbers.find { |n| n.even? }
puts even_number  # 2

# Find all elements satisfying condition
even_numbers = numbers.select { |n| n.even? }
puts even_numbers.inspect  # [2, 4, 6, 8, 10]

# Find elements not satisfying condition
odd_numbers = numbers.reject { |n| n.even? }
puts odd_numbers.inspect  # [1, 3, 5, 7, 9]

# Find element index
index = numbers.index(5)
puts index  # 4

# Find index of element satisfying condition
index = numbers.index { |n| n > 5 }
puts index  # 5 (index of first element greater than 5)

Array Filtering and Grouping

ruby
# Use take and drop
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
puts numbers.take(3).inspect   # [1, 2, 3] (take first 3)
puts numbers.drop(3).inspect   # [4, 5, 6, 7, 8, 9, 10] (skip first 3)

# Use take_while and drop_while
puts numbers.take_while { |n| n < 5 }.inspect  # [1, 2, 3, 4]
puts numbers.drop_while { |n| n < 5 }.inspect  # [5, 6, 7, 8, 9, 10]

# Grouping
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
grouped = numbers.group_by { |n| n.even? ? "Even" : "Odd" }
puts grouped
# {"Odd"=>[1, 3, 5, 7, 9], "Even"=>[2, 4, 6, 8, 10]}

# Chunking
data = [1, 2, 3, 4, 5, 6, 7, 8]
chunks = data.each_slice(3).to_a
puts chunks.inspect  # [[1, 2, 3], [4, 5, 6], [7, 8]]

# Partitioning
partitioned = numbers.partition { |n| n.even? }
puts partitioned.inspect  # [[2, 4, 6, 8, 10], [1, 3, 5, 7, 9]]

🔧 Array Transformation

Mapping and Conversion

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

# Use map to transform each element
squared = numbers.map { |n| n * n }
puts squared.inspect  # [1, 4, 9, 16, 25]

# Use collect (alias for map)
doubled = numbers.collect { |n| n * 2 }
puts doubled.inspect  # [2, 4, 6, 8, 10]

# In-place modification (use map!)
numbers.map! { |n| n * 2 }
puts numbers.inspect  # [2, 4, 6, 8, 10]

# Flatten nested arrays
nested = [[1, 2], [3, 4], [5, 6]]
flattened = nested.flatten
puts flattened.inspect  # [1, 2, 3, 4, 5, 6]

# Deep flatten
deep_nested = [1, [2, [3, 4]], 5]
deep_flattened = deep_nested.flatten(1)  # Flatten only one level
puts deep_flattened.inspect  # [1, 2, [3, 4], 5]

Sorting and Reversing

ruby
# Number sorting
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
sorted_asc = numbers.sort
puts sorted_asc.inspect  # [1, 1, 2, 3, 4, 5, 6, 9]

sorted_desc = numbers.sort { |a, b| b <=> a }
puts sorted_desc.inspect  # [9, 6, 5, 4, 3, 2, 1, 1]

# Use sort_by to sort by specific condition
words = ["apple", "banana", "cherry", "date"]
sorted_by_length = words.sort_by { |word| word.length }
puts sorted_by_length.inspect  # ["date", "apple", "cherry", "banana"]

# Reverse array
reversed = numbers.reverse
puts reversed.inspect  # [6, 2, 9, 5, 1, 4, 1, 3]

# Reverse in-place
numbers.reverse!
puts numbers.inspect   # [6, 2, 9, 5, 1, 4, 1, 3]

# Remove duplicate elements
duplicates = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unique = duplicates.uniq
puts unique.inspect  # [1, 2, 3, 4]

# Remove duplicates by condition
people = [
  {name: "Zhang San", age: 25},
  {name: "Li Si", age: 30},
  {name: "Zhang San", age: 28}
]
unique_by_name = people.uniq { |person| person[:name] }
puts unique_by_name.inspect
# [{:name=>"Zhang San", :age=>25}, {:name=>"Li Si", :age=>30}]

🔁 Array Iteration

Basic Iteration

ruby
fruits = ["Apple", "Banana", "Orange"]

# Use each to traverse
fruits.each { |fruit| puts "I like to eat #{fruit}" }
# I like to eat Apple
# I like to eat Banana
# I like to eat Orange

# Use each_with_index to get index
fruits.each_with_index do |fruit, index|
  puts "#{index + 1}. #{fruit}"
end
# 1. Apple
# 2. Banana
# 3. Orange

# Use reverse_each for reverse traversal
fruits.reverse_each { |fruit| puts fruit }
# Orange
# Banana
# Apple

Advanced Iteration

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

# Use map for transformation
squared = numbers.map { |n| n ** 2 }
puts squared.inspect  # [1, 4, 9, 16, 25]

# Use each_with_object to accumulate results
sum = numbers.each_with_object(0) { |n, total| total += n }
puts sum  # 15

# Use reduce/inject for accumulation
sum = numbers.reduce(0) { |total, n| total + n }
puts sum  # 15

product = numbers.reduce(1) { |total, n| total * n }
puts product  # 120

# Use reduce shorthand
sum = numbers.reduce(:+)
product = numbers.reduce(:*)

# Use zip to merge arrays
letters = ["a", "b", "c"]
numbers = [1, 2, 3]
combined = letters.zip(numbers)
puts combined.inspect  # [["a", 1], ["b", 2], ["c", 3]]

# Use transpose to transpose array
matrix = [[1, 2, 3], [4, 5, 6]]
transposed = matrix.transpose
puts transposed.inspect  # [[1, 4], [2, 5], [3, 6]]

🎯 Array Practice Examples

Data Processing Pipeline

ruby
class DataProcessor
  def initialize(data)
    @data = data
  end
  
  # Chained method calls
  def filter(&block)
    DataProcessor.new(@data.select(&block))
  end
  
  def map(&block)
    DataProcessor.new(@data.map(&block))
  end
  
  def sort(&block)
    DataProcessor.new(@data.sort(&block))
  end
  
  def take(n)
    DataProcessor.new(@data.take(n))
  end
  
  def result
    @data
  end
end

# Use data processing pipeline
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = DataProcessor.new(numbers)
  .filter { |n| n.even? }
  .map { |n| n ** 2 }
  .sort { |a, b| b <=> a }
  .take(3)
  .result

puts result.inspect  # [100, 64, 36]

Array Statistical Analysis

ruby
class ArrayStatistics
  def initialize(array)
    @array = array
  end
  
  # Calculate mean
  def mean
    return 0 if @array.empty?
    @array.sum.to_f / @array.length
  end
  
  # Calculate median
  def median
    return nil if @array.empty?
    sorted = @array.sort
    length = sorted.length
    if length.odd?
      sorted[length / 2]
    else
      (sorted[length / 2 - 1] + sorted[length / 2]) / 2.0
    end
  end
  
  # Calculate mode
  def mode
    return nil if @array.empty?
    frequency = Hash.new(0)
    @array.each { |n| frequency[n] += 1 }
    max_frequency = frequency.values.max
    frequency.select { |k, v| v == max_frequency }.keys
  end
  
  # Calculate variance
  def variance
    return 0 if @array.empty?
    avg = mean
    sum = @array.reduce(0) { |total, n| total + (n - avg) ** 2 }
    sum / @array.length
  end
  
  # Calculate standard deviation
  def standard_deviation
    Math.sqrt(variance)
  end
  
  # Get statistical summary
  def summary
    {
      count: @array.length,
      mean: mean,
      median: median,
      mode: mode,
      min: @array.min,
      max: @array.max,
      range: @array.max - @array.min,
      variance: variance,
      standard_deviation: standard_deviation
    }
  end
end

# Use statistical analysis
data = [1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 8, 9]
stats = ArrayStatistics.new(data)
puts stats.summary
# {:count=>12, :mean=>4.75, :median=>5.0, :mode=>[5], :min=>1, :max=>9, :range=>8, :variance=>5.6875, :standard_deviation=>2.384842971765449}

Array Paginator

ruby
class ArrayPaginator
  def initialize(array, per_page = 10)
    @array = array
    @per_page = per_page
  end
  
  # Get total pages
  def total_pages
    (@array.length.to_f / @per_page).ceil
  end
  
  # Get data for specified page
  def page(page_number)
    return [] if page_number < 1 || page_number > total_pages
    
    start_index = (page_number - 1) * @per_page
    end_index = start_index + @per_page - 1
    @array[start_index..end_index]
  end
  
  # Check if has next page
  def has_next_page?(current_page)
    current_page < total_pages
  end
  
  # Check if has previous page
  def has_prev_page?(current_page)
    current_page > 1
  end
  
  # Get next page
  def next_page(current_page)
    current_page + 1 if has_next_page?(current_page)
  end
  
  # Get previous page
  def prev_page(current_page)
    current_page - 1 if has_prev_page?(current_page)
  end
end

# Use paginator
data = (1..100).to_a
paginator = ArrayPaginator.new(data, 10)

puts "Total pages: #{paginator.total_pages}"  # Total pages: 10
puts "Page 1: #{paginator.page(1).inspect}"  # Page 1: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
puts "Page 5: #{paginator.page(5).inspect}"  # Page 5: [41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
puts "Has next page(5): #{paginator.has_next_page?(5)}"  # Has next page(5): true
puts "Next page(5): #{paginator.next_page(5)}"  # Next page(5): 6

📚 Next Steps

After mastering Ruby array operations, it is recommended to continue learning:

Continue your Ruby learning journey!

Content is for learning and research only.