What is an Array?

An array is an ordered list of elements that can be of any type. You can define an array by placing a list of elements between brackets like so:

irb :001 > [1, 'Bob', 4.33, 'another string']

You'll notice that the above array has strings, an integer, and a float. Arrays can have anything in them (even other arrays!). Now we need to save this array in a variable so we can play with it.

irb :002 > array = [1, 'Bob', 4.33, 'another string']

We'd like to find the first element of the array. We can just use the first method.

irb :003 > array.first
=> 1

What about the last element?

irb :004 > array.last
=> "another string"

But what if we want to find the third element?

Arrays are what we call indexed lists. That means that each slot in an array is numbered. You can reference any element by its index number. The syntax to do this is typing the array name with the index in brackets [] directly following. Let's try it out.

irb :005 > array[3]

What would you expect the above code to return? Type it into irb and see what you get.

Are you surprised? You probably thought that you were going to get the number 4.33 back, but instead, you got "another string". That's because all array indices start with the number 0. Try this in irb.

irb :006 > array[2]
=> 4.33

Now that's more like it. It's a little strange, but you'll get used to it.

Modifying Arrays

Let's say you wanted to add or remove something from an array. There are a few methods that will help you perform these operations.

If you'd like to take the last item off of an array permanently, you can use the pop method.

irb :007 > array.pop
=> "another string"
irb :008 > array
=> [1, "Bob", 4.33]

Note that when we called the pop method, the original array variable was modified (i.e., this is a method that mutates the caller), but the returned value is the popped element, as shown in the first line above. This is a critical distinction to understand. Make sure you distinguish between the value returned by an expression, and what the expression is actually doing.

Mutating the caller is similar to mutating arguments, but applies to the object used to call a method. For instance, in array.pop, the array specified by array is used to call the pop method. The difference is that mutating an argument alters the value of an object passed to a method as an argument, while mutating the caller modifies the object used to call the method.

If you'd like to add that item back to the array permanently, you can use the push method and send it the parameters you'd like to add.

irb :009 > array.push("another string")
=> [1, "Bob", 4.33, "another string"]

Another way to do the above would be with the shovel operator (<<).

irb :010 > array.pop
=> "another string"
irb :011 > array << "another string"
=> [1, "Bob", 4.33, "another string"]

Both the push and the << methods mutate the caller, so the original array is modified.

Often you'll have an array and you'll want to operate on many of the elements in the array the same way. Ruby has many methods that do these type of operations.

The map method iterates over an array applying a block to each element of the array and returns a new array with those results. The irb session below shows how to use map to get the square of all numbers in an array. The collect method is an alias to map - they do the same thing.

irb :001 > a = [1, 2, 3, 4]
=> [1, 2, 3, 4]
irb :002 > { |num| num**2 }
=> [1, 4, 9, 16]
irb :003 > a.collect { |num| num**2 }
=> [1, 4, 9, 16]
irb :004 > a
=> [1, 2, 3, 4]

You'll notice that after performing these methods there is no change to the initial array. These methods are not destructive (i.e., they don't mutate the caller). How do you know which methods mutate the caller and which ones don't? You have to use the methods and pay attention to the output in irb; that is, you have to memorize or know through using it.

The delete_at method can be helpful if you'd like to eliminate the value at a certain index from your array. You'll want to be careful with this one, because it modifies your array destructively. Once you call this method, you are changing your array permanently.

irb :005 > a.delete_at(1)
=> 2
irb :006 > a
=> [1, 3, 4]

As a side note, sometimes you will know the value that you want to delete, but not the index. In these situations you will want to use the delete method. The delete method permanently deletes all instances of the provided value from the array.

irb :007 > my_pets = ["cat", "dog", "bird", "cat", "snake"]
=> ["cat", "dog", "bird", "cat", "snake"]
irb :008 > my_pets.delete("cat")
=> "cat"
irb :009 > my_pets
=> ["dog", "bird", "snake"]

Another useful method is the uniq method. This iterates through an array, deletes any duplicate values that exist, then returns the result as a new array.

irb :010 > b = [1, 1, 2, 2, 3, 3, 4, 4]
=> [1, 1, 2, 2, 3, 3, 4, 4]
irb :011 > b.uniq
=> [1, 2, 3, 4]
irb :012 > b
=> [1, 1, 2, 2, 3, 3, 4, 4]

Once again, notice that the uniq method did not modify the original b array; it returned a new array with the duplicates removed.

If you add the bang suffix (!) to this method, you can perform the uniq method destructively. Much like the way the delete method works.

irb :013 > b = [1, 1, 2, 2, 3, 3, 4, 4]
=> [1, 1, 2, 2, 3, 3, 4, 4]
irb :014 > b.uniq!
=> [1, 2, 3, 4]
irb :015 > b
=> [1, 2, 3, 4]

uniq and uniq! are two different methods for Ruby Arrays. You cannot simply append a ! onto any method and achieve a destructive operation.

Iterating Over an Array

We talked in the loop section about using each to iterate over an array. The Ruby standard library has many similar methods. Let's take a look at the select method. This method iterates over an array and returns a new array that includes any items that return true to the expression provided. That's a mouthful. As always, looking at code is more helpful than using a bunch of words.

irb :001 > numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
irb :002 > { |number| number > 4 }
=> [5, 6, 7, 8, 9, 10]
irb :003 > numbers
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

The select method selects all of the numbers that are greater than 4 and returns them in an array. It does not mutate the caller (the original numbers array is unmodified).

Methods With a !

The bang suffix (!) at the end of the method name usually indicates that the method will change (or mutate) the caller permanently. Unfortunately this is not always the case. It is a good rule to be wary of any method that has the bang suffix and to make sure to check the Ruby documentation to see if it will behave destructively (the word "destructive" here just means mutating the caller).

Also, please note that there are methods like pop and push that are destructive, but do not have a ! at the end. It's a little confusing in the beginning, but as you write more programs in Ruby, you'll start to get a feel for which methods are destructive and which are not.

Mutating the Caller and Arguments

We talked about mutating the caller and mutating arguments earlier and showed examples to go along with it. This concept is so important that we wanted to cover it in even more depth. It's important to keep the concept in mind since it is possible that a method can unexpectedly change an object used as the caller or as an argument. This can be a major source of confusion which is why it's important to know what a method is doing to its arguments and calling object, and to know what that method returns.

We also wanted to revisit destructive methods within the context of using a method. Look at the two methods below and see if you can decipher why the first method mutates the argument, but the second one doesn't.

def mutate(arr)

def not_mutate(arr) { |i| i > 3 }

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

puts a

The last line will output 1, 2, 3, 4, and 5. The mutate method performed a destructive action (i.e., pop) on its argument, thereby modifying the a array, even though a was initialized outside of the method. Therefore, the 6 element was popped out of the original array. The not_mutate method performed a non-destructive action (i.e., select), and therefore the original variable was unmodified.

It's worth noting that inside mutate, arr.pop mutates its caller. That, in turn, mutates the argument passed to mutate. However, inside not_mutate, does not mutate its caller, so not_mutate doesn't mutate its argument either.

Nested Arrays

We talked earlier about arrays being able to contain anything. You can also create arrays with arrays inside of them. Let's say you were having a sand volleyball tournament and wanted to keep track of all of the teams that were playing. You might create an array like this.

irb :001 > teams = [['Joe', 'Steve'], ['Frank', 'Molly'], ['Dan', 'Sara']]
=> [["Joe", "Steve"], ["Frank", "Molly"], ["Dan", "Sara"]]

Then you could find the teams by index.

irb :002 > teams[1]
=> ["Frank", "Molly"]

You could also have an array of hashes too! We won't get into too many crazy examples here, but play around with it in irb.

Comparing Arrays

You can compare arrays for equality using the == operator.

irb :001 > a = [1, 2, 3]
=> [1, 2, 3]
irb :002 > b = [2, 3, 4]
=> [2, 3, 4]
irb :003 > a == b
=> false
irb :004 > b.pop
=> 4
irb :005 > b.unshift(1)
=> [1, 2, 3]
irb :006 > a == b
=> true

You'll notice that we used the unshift method in this example. unshift is a lot like the push method. However, instead of adding values to the end of the list, unshift adds values to the start of the list.


The to_s method is used to create a string representation of an array. Ruby does this behind the scenes when you use string interpolation to print an array to the screen.

irb :001 > a = [1, 2, 3]
=> [1, 2, 3]
irb :002 > "It's as easy as #{a}"
=> "It's as easy as [1, 2, 3]"

In order to get our array to print properly, Ruby is calling the to_s method on our array and adding it into the string.

Common Array Methods

This section will introduce you to some common methods that Ruby has built-in to its Array class. You should bookmark that documentation page as it's probably something you'll want to refer to often.


The include? method checks to see if the argument given is included in the array. It has a question mark at the end of it which usually means that you should expect it to return a boolean value, true or false. (Such methods are called predicates.) Just like the methods that end in a "!", this is strictly by convention only and not a property of the language.

irb :001 > a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
irb :002 > a.include?(3)
=> true
irb :003 > a.include?(6)
=> false


The flatten method can be used to take an array that contains nested arrays and create a one-dimensional array.

irb: 001 > a = [1, 2, [3, 4, 5], [6, 7]]
=> [1, 2, [3, 4, 5], [6, 7]]
irb: 002 > a.flatten
=> [1, 2, 3, 4, 5, 6, 7]

Is the flatten method destructive? Find out for yourself in either irb, or by consulting the Array documentation.


The each_index method iterates through the array much like the each method, however the variable represents the index number as opposed to the value at each index. It passes the index of the element into the block and you may do as you please with it. The original array is returned.

irb: 001 > a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
irb: 002 > a.each_index { |i| puts "This is index #{i}" }
This is index 0
This is index 1
This is index 2
This is index 3
This is index 4
=> [1, 2, 3, 4, 5]


Another useful method that works in a similar way to each_index is each_with_index.

irb: 001 > a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
irb: 002 > a.each_with_index { |val, idx| puts "#{idx+1}. #{val}" }
1. 1
2. 2
3. 3
4. 4
5. 5
=> [1, 2, 3, 4, 5]

each_with_index gives us the ability to manipulate both the value and the index by passing in two parameters to the block of code. The first is the value and the second is the index. You can then use them in the block.


The sort method is a handy way to order an array. It returns a sorted array.

irb :001 > a = [5, 3, 8, 2, 4, 1]
=> [5, 3, 8, 2, 4, 1]
irb :002 > a.sort
=> [1, 2, 3, 4, 5, 8]

Once again, test in irb to see if the sort method is destructive. (It's not, but test it out for yourself.) We won't remind you to test this in the future, but when you see methods like this in the future, ask yourself "is this method returning new data, or is the original data being modified?".


The product method can be used to combine two arrays in an interesting way. It returns an array that is a combination of all elements from all arrays.

irb :001 > [1, 2, 3].product([4, 5])
=> [[1, 4], [1, 5], [2, 4], [2, 5], [3, 4], [3, 5]]

There are too many interesting methods to cover, but we wanted to give you a taste of the power of Ruby arrays and the many handy methods that come built-in with Ruby. If you ever think "I want my array to...", there is probably a method that already does this. First, check the documentation.

each vs map


each provides a simple way of iterating over a collection in Ruby and is preferred to using the for loop. The each method works on objects that allow for iteration and is commonly used along with a block. If given a block, each runs the code in the block once for each element in the collection and returns the collection it was invoked on. If no block is given, it returns an Enumerator. Let's look at some simple examples:

irb :001 > a = [1, 2, 3]
irb :002 > a.each { |e| puts e }
=> [1, 2, 3]

The above shows the most common way of using each. We're iterating over each element on the array a and printing it out. Finally it returns [1, 2, 3].

We can also modify the elements in a and print them out:

irb :003 > a = [1, 2, 3]
irb :004 > a.each { |e| puts e + 2 }
=> [1, 2, 3]

Again, we print out the modified values and return the original collection a.

In this chapter, so far, we've been using curly brace blocks exclusively. Don't forget that you can also use do...end as well:

irb :005 > a = [1, 2, 3]
irb :006 > a.each do |e|
irb :007 *   puts e + 2
irb :008 * end
=> [1, 2, 3]

Here is a final example with no block; an Enumerator is returned:

irb :009 > a = [1, 2, 3]
irb :010 > a.each
=> #<Enumerator: ...>


map also works on objects that allow for iteration. Like each, when given a block it invokes the given block once for each element in the collection. Where it really differs from each is the returned value. map creates and returns a new array containing the values returned by the block. Let's see it in action:

irb :011 > a = [1, 2, 3]
irb :012 > { |x| x**2 }
=> [1, 4, 9]

We square each element in the block and create a new array containing the returned values by the block. Finally the new array is returned.

To really examine that map creates a new array consisting of the returned value of the block, let's see an example with map and puts:

irb :013 > a = [1, 2, 3]
irb :014 > { |x| puts x**2 }
=> [nil, nil, nil]

Because puts returns nil every time the block is invoked nil is returned which makes up the values in the newly created returned array.

Finally, if no block is given, map returns an Enumerator:

irb :015 > a = [1, 2, 3]
irb :016 >
=> #<Enumerator: ...>

each and map are important methods to know but can be quite confusing in the beginning. Another way to remember these methods: use each for iteration and map for transformation.


Arrays are an extremely valuable data set. They can be used to store many different kinds of data and you'll see them very often in the wild. Ruby's array class has lots of built-in methods that can be used to perform many of the daily functions that programmers use. Let's practice working with arrays for a bit with some exercises.


  1. Below we have given you an array and a number. Write a program that checks to see if the number appears in the array.

    arr = [1, 3, 5, 7, 9, 11]
    number = 3


    arr.each do |num|
      if num == number
        puts "#{number} is in the array."
    # ... or...
    if arr.include?(number)
      puts "#{number} is indeed in the array."

    Video Walkthrough

    Please register to play this video

  2. What will the following programs return? What is the value of arr after each?

    1. arr = ["b", "a"]
       arr = arr.product(Array(1..3))
    2. arr = ["b", "a"]
       arr = arr.product([Array(1..3)])


    1. returns 1
        arr =  [["b"], ["b", 2], ["b", 3], ["a", 1], ["a", 2], ["a", 3]]
    2. returns [1, 2, 3]
        arr = [["b"], ["a", [1, 2, 3]]]

    Video Walkthrough

    Please register to play this video

  3. How do you return the word "example" from the following array?

    arr = [["test", "hello", "world"],["example", "mem"]]


    Either of the following solutions will work:


    as well as several other variations. The video walkthrough talks about the first solution.

    Video Walkthrough

    Please register to play this video

  4. What does each method return in the following example?

    arr = [15, 7, 18, 5, 12, 8, 5, 1]
    1. arr.index(5)
    2. arr.index[5]
    3. arr[5]


    1. 3
    2. NoMethodError: undefined method `[]' for #<Enumerator: [15, 7, 18, 5, 12, 8, 5, 1]:index>
      from (irb):81
      from /usr/local/rvm/rubies/ruby-2.5.3/bin/irb:16:in `<main>'
    3. 8

    Video Walkthrough

    Please register to play this video

  5. What is the value of a, b, and c in the following program?

    string = "Welcome to America!"
    a = string[6]
    b = string[11]
    c = string[19]


    a = "e"
    b = "A"
    c = nil

    Notice that when you reference an index of a string that is beyond the length of the string, Ruby returns nil and doesn't throw an error.

    Video Walkthrough

    Please register to play this video

  6. You run the following code...

    names = ['bob', 'joe', 'susan', 'margaret']
    names['margaret'] = 'jody'

    ...and get the following error message:

    TypeError: no implicit conversion of String into Integer
      from (irb):2:in `[]='
      from (irb):2
      from /Users/username/.rvm/rubies/ruby-2.5.3/bin/irb:12:in `<main>'

    What is the problem and how can it be fixed?


    You are attempting to set the value of an item in an array using a string as the key. Arrays are indexed with integers, not strings. You would modify the array by doing the following:

    names[3] = 'jody'   # => ["bob", "joe", "susan", "jody"]

    Video Walkthrough

    Please register to play this video

  7. Use the each_with_index method to iterate through an array of your creation that prints each index and value of the array.


    top_five_games = ["mario brothers",
                      "excite bike",
                      "ring king",
                      "double dragon"]
    top_five_games.each_with_index do | game, index |
      puts "#{index + 1}. #{game}"

    Note: The problem description and solution aren't completely in agreement. The description asks us to print the index of each element, but the solution prints the index plus 1. We've left this disagreement as-is for consistency with the video. Feel free to choose which approach you want to use.

    Video Walkthrough

    Please register to play this video

  8. Write a program that iterates over an array and builds a new array that is the result of incrementing each value in the original array by a value of 2. You should have two arrays at the end of this program, The original array and the new array you've created. Print both arrays to the screen using the p method instead of puts.


    arr = [1, 2, 3, 4, 5]
    new_arr = []
    arr.each do |n|
      new_arr << n + 2
    p arr
    p new_arr


    arr = [1, 2, 3, 4, 5]
    new_arr = do |n|
      n + 2
    p arr
    p new_arr

    Video Walkthrough

    Please register to play this video