Working with Ruby Arrays: Creation, Iteration, and Methods
Working with Ruby arrays is one of the first skills every Ruby developer learns because they are the most common ordered data structure in the language. They store collections of items (numbers, strings, objects, or even nested arrays) in an ordered list with integer indices starting at zero. This tutorial covers what you need to work with arrays effectively, from the basic literal syntax to the higher-order operations the Enumerable mixin layers on top.
Intro context
Arrays are the default answer whenever you need an ordered list in Ruby. They show up in APIs, parsed files, user input, database records, and anything else that naturally comes back as “a bunch of things.” Once you know how to create them, index into them, and transform them, a lot of Ruby code becomes easier to read because the data structure is already familiar.
The same patterns show up in Ruby strings when you split text into pieces and in Ruby hashes when you move from ordered lists to key-value pairs. Thinking about arrays alongside those two topics helps you see where each structure fits and why Ruby uses them so often.
We start with creation and indexing, move through mutation and the standard <<, push, pop, shift, unshift operations, then graduate to each, map, select, reject, and inject. The set operators |, &, and - get their own section because they are quietly useful for deduplication and difference checks. The tutorial closes with two recurring pitfalls: shared references when you assign an array to a new variable, and the difference between mutating and non-mutating method names (the ones ending in !).
A one-line preview shows how quickly you can go from an empty array to a filtered result:
numbers = [5, 12, 3, 8, 1]
evens = numbers.select { |n| n.even? } # => [12, 8]
For deeper coverage of individual methods, see the Enumerable map reference and the array-reject reference. Those references are useful once you want the quick syntax check after you already understand how the collection itself behaves.
The official Ruby Array documentation covers every method in detail and is a good reference to keep bookmarked.
Creating and working with arrays
The simplest way to create an array is using square brackets:
Array literals are the most common form because they are short and easy to scan. If you are writing everyday Ruby, this is the form you will probably use most often. It also makes mixed collections easy to express when the items are not all the same type.
fruits = ["apple", "banana", "cherry"]
numbers = [1, 2, 3, 4, 5]
mixed = [1, "two", :three, true]
You can also use the Array.new constructor:
Array.new is useful when you want to start from an empty array or prefill a fixed number of slots. It gives you a slightly more explicit way to describe the shape of the array, which can be handy in setup code or when you are building a container programmatically.
empty = Array.new
three_nils = Array.new(3) # => [nil, nil, nil]
with_defaults = Array.new(3, 0) # => [0, 0, 0]
Ruby arrays can hold objects of any type, and they maintain the order in which you add items.
That flexibility is one of the reasons ordered lists appear so often in Ruby programs. You can store strings, numbers, symbols, objects, or even other arrays, and Ruby will keep the items in insertion order unless you sort or change them yourself.
Accessing elements
Array indices start at zero. Use brackets to access elements:
Index access is one of the first things to learn because it tells you how Ruby thinks about ordered data. The zero-based index is consistent across the language, so once you understand it here, you will see the same idea in loops and string slicing too.
fruits = ["apple", "banana", "cherry", "date"]
fruits[0] # => "apple"
fruits[1] # => "banana"
fruits[-1] # => "date" (last element)
fruits[-2] # => "cherry" (second to last)
fruits.first # => "apple"
fruits.last # => "date"
fruits[1, 2] # => ["banana", "cherry"] # slice
Negative indices count from the end of the array, making it easy to access elements from the back without knowing the array length.
That feature is especially useful when you only care about the last item or the item just before it. Instead of calculating the size first, you can jump straight to the position you need.
Modifying arrays
Ruby provides many methods to add, remove, and modify elements:
Mutation is one of the big reasons arrays are practical. You can grow the list, trim it, or reshape it in place without rebuilding the whole structure. That is handy in scripts and application code alike because it keeps the control flow simple.
numbers = [1, 2, 3]
numbers.push(4) # => [1, 2, 3, 4]
numbers << 5 # => [1, 2, 3, 4, 5] # shovel operator
numbers.pop # => 5, numbers is now [1, 2, 3, 4]
numbers.shift # => 1, numbers is now [2, 3, 4]
numbers.unshift(0) # => [0, 2, 3, 4]
numbers.insert(1, 99) # => [0, 99, 2, 3, 4]
numbers.delete(99) # => [0, 2, 3, 4]
The shovel operator (<<) is particularly idiomatic in Ruby and is used frequently.
It is worth getting comfortable with << because you will see it constantly in Ruby code. The operator reads naturally when you are appending one item at a time, and it keeps the code short enough that the intent stays obvious.
How do you iterate over arrays in Ruby?
The each method is the most common way to iterate:
Iteration is where arrays become more than just storage. Once you can walk through the list, you can inspect, format, filter, and transform the data without needing to manually manage an index in most cases.
fruits = ["apple", "banana", "cherry"]
fruits.each do |fruit|
puts fruit
end
# Prints: apple, banana, cherry (each on new line)
# Short block syntax
fruits.each { |f| puts f.upcase }
Use map when you need to transform each element:
map is the transformation tool, not the “just look at the value” tool. That distinction matters because it helps you choose between methods that return the original array and methods that return something new.
numbers = [1, 2, 3, 4, 5]
squares = numbers.map { |n| n ** 2 }
# => [1, 4, 9, 16, 25]
doubled = numbers.map(&:*)
# => [2, 4, 6, 8, 10]
The map method returns a new array with the transformed values, leaving the original unchanged.
That non-destructive behavior is usually what you want when you are building a pipeline of values. It keeps the original data intact and makes the result of the transformation easy to store in a new variable.
Filtering and finding
Select elements based on conditions:
Filtering is where arrays start to feel like a query language. Instead of thinking about the whole collection, you describe the rule for the items you want and let Ruby build the new list for you.
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
even = numbers.select { |n| n.even? }
# => [2, 4, 6, 8, 10]
odd = numbers.reject { |n| n.even? }
# => [1, 3, 5, 7, 9]
first_big = numbers.find { |n| n > 5 }
# => 6
The find method returns the first matching element, while select returns all matches.
That difference is small but important. If you only need one result, find is usually clearer. If you need the whole group, select keeps the matching elements together in a new array.
Useful array methods
Ruby arrays come with many built-in methods:
These helper methods are the ones you reach for when you want quick facts about the collection. They make it easy to ask about size, membership, ordering, and summary values without writing a loop yourself.
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
numbers.length # => 8
numbers.count # => 8
numbers.empty? # => false
numbers.include?(5) # => true
numbers.sort # => [1, 1, 2, 3, 4, 5, 6, 9]
numbers.reverse # => [6, 2, 9, 5, 4, 1, 3, 1]
numbers.sum # => 31
numbers.max # => 9
numbers.min # => 1
Common operations like checking if an array contains something, finding its size, or getting min/max values are built-in.
In practice, that means arrays do a lot more than store data. They also give you a compact vocabulary for asking questions about the data, which keeps application code shorter and easier to test.
Combining arrays
Join arrays together:
Combining arrays is useful when you are merging two sources of ordered data or when you want to describe set-like operations on lists. The operators are short, but they cover a lot of everyday Ruby tasks.
a = [1, 2]
b = [3, 4]
a + b # => [1, 2, 3, 4]
a.concat(b) # => [1, 2, 3, 4], a is modified
[1, 2] | [2, 3] # => [1, 2, 3] # union
[1, 2, 2, 3] & [2, 3, 3] # => [2, 3] # intersection
[1, 2] - [2] # => [1] # difference
The union and intersection operators are useful for set operations on arrays.
They are especially handy when you need to remove duplicates or compare overlapping values. If the data should behave more like a mathematical set than a strict list, these operators are the right fit.
Common pitfalls
One mistake beginners make is confusing each with map. The each method returns the original array, while map returns a new array with transformed values:
This mistake is common because the two methods look similar at first glance. The safest habit is to stop and ask whether you want to observe each element or create a transformed copy. That one question usually tells you which method to choose.
numbers = [1, 2, 3]
numbers.each { |n| n * 2 } # => [1, 2, 3] # ignored return value
numbers.map { |n| n * 2 } # => [2, 4, 6] # new array
Another issue involves modifying an array while iterating over it. If you need to modify during iteration, work with a copy:
Changing the collection while walking through it can produce confusing results because the list is shifting under the loop. Working with a copy keeps the iteration stable and makes the intent easier to understand later.
numbers = [1, 2, 3, 4, 5]
# Bad - unexpected behavior
numbers.each { |n| numbers.delete(n) if n.even? }
# Good - work with a copy
numbers.dup.each { |n| numbers.delete(n) if n.even? }
When to use arrays
Arrays are perfect when you need:
- An ordered collection of items
- Quick access by index
- Iterating over a list of similar items
- Simple data structures
For key-value pairs, use hashes instead. For sorted data with fast lookup, consider sets.
That tradeoff is worth remembering because Ruby gives you a few overlapping tools. Arrays are the best match when order matters and the data is naturally a list. If the order does not matter or you need named values, another structure may be a better fit.
Summary
Working with Ruby arrays is versatile and essential in the language. They provide efficient indexed access, powerful iteration methods, and work naturally with Ruby’s enumerable module. Master these basics and you’ll manipulate data confidently in any Ruby project.
What’s next
The next tutorial moves from ordered lists to named lookups, which means you will see how hashes solve a different kind of data problem. If arrays are about position, hashes are about labels, and understanding both makes Ruby collections much easier to use in practice.
Forward link
Now that you understand arrays, the next logical step is learning about hashes—Ruby’s key-value data structure. Head to Hashes in Ruby to continue your journey through Ruby fundamentals.