← Reference · Nestor G Pestelos Jr · Print this page
Programming Languages · Ruby
Ruby Array Operations
Reference entry · last updated September 22, 2026
Ruby array operations are the methods of the Array class, an ordered, integer-indexed collection of objects. They group into construction, access, mutation, selection, transformation, ordering, and conversion. The class also includes Enumerable, so the shared iteration methods apply to arrays as well.[1][2]
First principles and definitions
Order and index
An array is ordered and indexed by integers starting at 0. A negative index counts from the end, so -1 is the last element. An array tracks its own length, and an out-of-range read through [] returns nil rather than raising, which is the difference between [] and fetch.[1]
[10, 20, 30][-1] # => 30 [10, 20, 30][9] # => nil [10, 20, 30].fetch(9) # IndexError [10, 20, 30].fetch(9, :d) # => :d
Destructive and non-destructive
Some methods have plain and bang forms: sort and sort!. sort returns a new array; sort! changes the receiver and returns it, even when the order stays the same. pop removes an element without a bang, and select! returns nil when nothing changes. << also changes the receiver.[1]
a = [3, 1, 2] a.sort # => [1, 2, 3] a # => [3, 1, 2] a.sort! # => [1, 2, 3] a # => [1, 2, 3]
Construction
The literal [1, 2, 3] and %w[a b c] cover most cases. Array.new(n) builds n nil elements, and Array.new(n, obj) fills with one shared object. When the fill is mutable, pass a block instead, so each slot receives a distinct object.[1]
Array.new(3) # => [nil, nil, nil]
Array.new(3, []) # three references to one array
Array.new(3) { [] } # three distinct arrays
a = Array.new(3, [])
a[0] << 1
a # => [[1], [1], [1]]
Access
Indexing reads one element or a slice. The helper methods read from the ends or take a count, and dig walks nested arrays without raising on a missing level.[1]
a = [10, 20, 30, 40] a[1] # => 20 a[1, 2] # => [20, 30] a[1..2] # => [20, 30] a.first # => 10 a.last # => 40 a.take(2) # => [10, 20] a.drop(2) # => [30, 40] [[1, [2, 3]]].dig(0, 1, 1) # => 3
values_at reads several indices at once, and sample reads a random element. [] returns nil for an out-of-range index; fetch raises IndexError or returns a supplied default.
Mutation
Append with push or <<, prepend with unshift, and insert at an offset with insert. pop and shift remove and return the last and first elements. concat appends another array in place; + returns a new array instead.[1]
a = [1, 2] a << 3 # => [1, 2, 3] a.unshift(0) # => [0, 1, 2, 3] a.insert(2, 9) # => [0, 1, 9, 2, 3] a.pop # => 3 a.shift # => 0 a.delete(9) # => 9, removes every 9 a.delete_at(0) # removes by index a.clear # => [] b = [1] c = b + [2] # new array; b unchanged b.concat([2]) # b is now [1, 2]
Selection and search
Selection returns a new array of the elements that match, and the bang variants filter in place. compact removes nil, uniq removes duplicates, and flatten collapses nested arrays. find returns the first match or nil, while find_all is an alias for select.[1][2]
[1, 2, 3, 4].select { |x| x.even? } # => [2, 4]
[1, 2, 3, 4].reject { |x| x.even? } # => [1, 3]
[1, 2, 3].find { |x| x > 1 } # => 2
[1, 2, 3].include?(2) # => true
[1, nil, 2].compact # => [1, 2]
[1, 1, 2].uniq # => [1, 2]
[[1, [2]], 3].flatten # => [1, 2, 3]
[1, 2, 3].partition { |x| x.odd? } # => [[1, 3], [2]]
Transformation
These methods map the array into a new shape. map transforms each element, reduce folds the array to one value, and each_with_object carries an accumulator through the iteration. group_by and partition split the array by a block result, and tally counts occurrences of each distinct element.[1][2]
[1, 2, 3].map { |x| x * 2 } # => [2, 4, 6]
[1, 2, 3].reduce(0) { |sum, x| sum + x } # => 6
[1, 2, 3].sum # => 6
[1, 2, 3, 4].each_slice(2).to_a # => [[1, 2], [3, 4]]
[1, 2, 3, 4].group_by { |x| x.even? } # => {false=>[1, 3], true=>[2, 4]}
[1, 1, 2].tally # => {1=>2, 2=>1} (Ruby 2.7+)
filter_map combines a filter and a map in one pass (Ruby 2.7+). flat_map maps and then flattens one level. zip pairs the array with others, and each_cons yields each consecutive window.
Ordering
sort orders by each element's own comparison, or by a two-argument block. sort_by maps each element to a key once and sorts by it. Neither is stable, so a deterministic order needs a unique final key component.[2]
[3, 1, 2].sort # => [1, 2, 3]
%w[apple pear fig].sort_by(&:length) # => ["fig", "pear", "apple"]
[3, 1, 2].reverse # => [2, 1, 3]
[1, 2, 3].min, [1, 2, 3].max # => 1, 3
[1, 2, 3].max_by(2) { |x| -x } # => [1, 2]
For a composite order, such as count descending then word ascending, see Ruby Composite Sort Keys.
Conversion
join turns an array of strings into one string, and to_h builds a hash from an array of pairs. The splat operator expands an array into arguments. Array() tries to_ary, then to_a, and wraps the value if neither converts it. nil becomes an empty array, and an existing array stays unchanged.[1]
%w[a b c].join("-") # => "a-b-c"
[[:a, 1], [:b, 2]].to_h # => {:a=>1, :b=>2}
Array(nil) # => []
Array([1, 2]) # => [1, 2]
Choosing an operation
- Keep the original: the plain form, such as
maporselect. - Update in place: the bang form, such as
map!orselect!. - One element:
findordetect; usefetchwhen a missing index should raise. - One value from many:
reduceorsum. - Order by a computed key:
sort_by; for two keys, see Ruby Composite Sort Keys. - Count per distinct element:
tally(Ruby 2.7+), or a hash accumulator, see Ruby Hash Accumulators. - The structure itself: see Ruby Enumerable Structures.
References
- ^ Ruby 3.3 core documentation, "Array." Free full text: docs.ruby-lang.org/en/3.3/Array.html
- ^ Ruby 3.3 core documentation, "Enumerable." Free full text: docs.ruby-lang.org/en/3.3/Enumerable.html