An Introduction into Arrays

Launch Academy

By Launch Academy

February 1, 2022

Lists

Lists are incredibly useful. You probably have a list of tasks you need to complete this week. Before you make a trip to the grocery store, you make a list of things to purchase so you won't forget anything. The menu at your favorite Thai restaurant is a list of dishes the kitchen is stocked to make. The roster for a classroom is a list of students that should be in attendance.

Programmers need lists, too. We just gave them a funny name.

Arrays

An array is just an ordered list. You can add items to the list. You can remove items from the list. And, because our lists exist in the magical realm of the computer, we can do plenty of crazy things with them. Such as, reverse the order of the items, replace items with specific attributes, sort them, or shuffle all the items around like a deck of cards.

Let's start calling our lists Arrays. That way Ruby will understand what we are talking about.

Array Basics

You will learn the most in this lesson by typing in the examples provided. Open up pry session and follow along.

If you don't have pry, you can gem install pry to get it. It's super awesome.

Or, you can always go with plain, old irb.

Creating Arrays

pry(main)> Array.new
=> []

Notice that when we called Array.new, we received back opening and closing square brackets: []. Programmers use lists, *ahem*, arrays, all the time. This is the shorthand notation for an empty array. We can create a new array this way:

pry(main)> []
=> []

An empty array is like a blank canvas. Let's create a new array with some tasks for us to accomplish, and assign the new array to a variable named to_do:

pry(main)> to_do = ["walk the dog", "buy milk", "learn about arrays"]
=> ["walk the dog", "buy milk", "learn about arrays"]

Array Methods

We can find out some interesting things about our array.

pry(main)> to_do.length
=> 3

pry(main)> to_do.first
=> "walk the dog"

pry(main)> to_do.last
=> "learn about arrays"

pry(main)> to_do.empty?
=> false

length, first, last, and empty? are all methods defined on the Array class. Read up on these methods in the Ruby documentation for arrays. I hinted at a few methods we could call on arrays earlier in this article. What other methods of the Array class might be useful? Pick out a few methods from the list of methods in the Array class and read about them and try them out in pry.

Accessing Items in Arrays

Arrays are a little bit funny about the way we access items. We can access an item in the array by providing an index, which starts at zero. We can ask an array what exists at any particular index by passing it a number in square brackets. Try this out:

pry(main)> to_do = ["walk the dog", "buy milk", "learn about arrays"]
=> ["walk the dog", "buy milk", "learn about arrays"]

pry(main)> to_do[1]
=> # what happens here?

Try out the code above. Don't worry, I'll still be here when you get back.

What did you expect to see when calling to_do[1]? What did you get in return? What happens when you try other numbers, such as 0? What does this experiment tell us about arrays?

Array indices start at zero, and go up to the length of the array minus one. to_do[0] will return the first item in the array. to_do[2] will give us the last item since the length is currently 3.

We can visually represent our array like so:

        +-----------+-----------+-----------+
        |           |           |           |
        |   "walk   |   "buy    |  "learn   |
array:  |    the    |   milk"   |   about   |
        |    dog"   |           |  arrays"  |
        |           |           |           |
        +-----------+-----------+-----------+
index:       [0]         [1]         [2]

What happens if we try to access to_do[3] in our array?

pry(main)> to_do[3]
=> nil

We get nil, which is Ruby's way of saying that nothing is there.

Right now, you might be asking yourself, "Why do we start counting at zero instead of one?" The answer to this is a bit complex. To explain it simply, think of each cell in the above diagram as a section of memory. If we know the location first cell, we can get the data in the first cell, "walk the dog". To get to the second cell from the first, we need to move exactly one cell to the right. To get to the third cell from the first, we need to move exactly two cells. This is the basis of pointer arithmetic and finding data in memory. In most every programming language, zero-based arrays indices are the norm.

Adding Items

The Shovel Operator << and push

Our array of things to do is growing. Let's amend our list to reflect the current list of tasks we need to accomplish:

pry(main)> to_do << "read the news"
=> ["walk the dog", "buy milk", "learn about arrays", "read the news"]

Here, we have introduced a new method we can use to add items to the end of an array. It is called the shovel operator, and it is represented by two less-than signs <<.

The other method we can use to put new items on to the end of the list is the push method. The shovel << and the push method are equivalent. They also exemplify the idea that there are many ways to achieve the same result when programming.

pry(main)> to_do.push("do laundry")
=> ["walk the dog", "buy milk", "learn about arrays", "read the news", "do laundry"]

Adding Arrays

We can combine arrays using the addition symbol:

pry(main)> ["walk the dog", "buy milk"] + ["learn about arrays", "read the news", "do laundry"]
=> ["walk the dog", "buy milk", "learn about arrays", "read the news", "do laundry"]

The unshift Method

What if we have a really important task that belongs at the beginning of our list? Well, via the unshift method, we can add items to the front of the array.

pry(main)> to_do.unshift("pay the rent!")
=> ["pay the rent!", "walk the dog", "buy milk", "learn about arrays", "read the news", "do laundry"]

The insert Method

What if after I learn about arrays, I want to learn more about Ruby? Well, we can insert a task into our ordered list of things to do! insert takes two arguments: first, the index of the position to insert the item, and second, the item to insert.

pry(main)> to_do.insert(4, "learn ruby")
=> ["pay the rent!", "walk the dog", "buy milk", "learn about arrays", "learn ruby", "read the news", "do laundry"]

The include? Method

What if I'm quite forgetful, and I can't remember if I already added "buy milk" to my array? Well, I could print it out and scan through it, but that wouldn't be efficient. I can use ruby code to check my list!

pry(main)> to_do.include?("buy milk")
=> true

pry(main)> to_do.include?("buy eggs")
=> false

The index Method

What if I want to find out the location of an item in my array of things to do? The index method does that for us:

pry(main)> to_do.index("pay the rent!")
=> 0

pry(main)> to_do.index("read the news")
=> 5

Reassigning Items in an Array

What if I'm lactose intolerant? Well, we can reassign specific elements in the array like so:

pry(main)> to_do[2] = "buy soy milk"
=> "buy soy milk"

pry(main)> to_do
=> ["pay the rent!", "walk the dog", "buy soy milk", "learn about arrays", "learn ruby", "read the news", "do laundry"]

It is great to know about all these methods we have available to us for inserting items into an array. We have covered quite a bit so far. Arguably, the most important of these is the shovel operator << and the include? method. You don't have to commit all of these methods to memory. Just know that they exist and where you can find them in the Ruby docs if you might need one of them in the future.

Removing Items

The shift Method

Fast forward. It is the future, and we have accomplished some of our tasks. We paid the rent, walked the dog, read the news, and finished the laundry. Let's start crossing items off of our virtual list.

pry(main)> to_do.shift
=> "pay the rent!"

pry(main)> to_do.shift
=> "walk the dog"

pry(main)> to_do
=> ["buy soy milk", "learn about arrays", "learn ruby", "read the news", "do laundry"]

Before calling shift

        +-----------+-----------+-----------+-----------+-----------+
        |           |           |           |           |           |
        |   "walk   |   "buy    |  "learn   |  "read    |  "do      |
array:  |    the    |   milk"   |   about   |   the     |  laundry" |
        |    dog"   |           |  arrays"  |   news"   |           |
        |           |           |           |           |           |
        +-----------+-----------+-----------+-----------+-----------+
index:       [0]         [1]         [2]         [3]         [4]

After calling shift

         +-----------+          +-----------+-----------+-----------+-----------+
         |           |          |           |           |           |           |
         |   "walk   |          |   "buy    |  "learn   |  "read    |  "do      |
return:  |    the    |  array:  |   milk"   |   about   |   the     |  laundry" |
         |    dog"   |          |           |  arrays"  |   news"   |           |
         |           |          |           |           |           |           |
         +-----------+          +-----------+-----------+-----------+-----------+
                        index:       [0]         [1]         [2]         [3]

The shift method allows us to remove an item from the front of our array. Imagine all of the items being shifted to the left by one place, with the first item being the return value.

The delete Method

pry(main)> to_do.delete("read the news")
=> "read the news"

pry(main)> to_do
=> ["buy soy milk", "learn about arrays", "learn ruby", "do laundry"]

The delete method is very powerful. It searches through our array, finds the item that matches what we told it to look for, and then removes and returns it. How awesome is that?

The pop Method

pry(main)> to_do.pop
=> "do laundry"

pry(main)> to_do
=> ["buy soy milk", "learn about arrays", "learn ruby"]

The pop method removes and returns the last item from our array. You can think of the pop method as the opposite of push, since push adds to then end of the array, and popremoves from the end of the array. unshift and shift are opposites too, except that they operate on the front of the array. To use an analogy: push is to pop, as unshift is toshift. Now you're talking like a programmer!

Iterating through Items in an Array

Let's say that I want to print out my to_do list in a nice format. I can find the length of my array with the length method. Knowing the length of my array, I can construct a whileloop, that indexes each item in my array and prints out the value.

puts "My To Do list:"
to_do = ["buy soy milk", "learn about arrays", "learn ruby"]
i = 0
while i < to_do.length
  print " * "
  puts to_do[i]
  i += 1
end

Let's stop for a second and ask ourselves what's going on with our variable i here. We're using it as a counter to keep track of some data, and in this case, namely the index of the element of the array. i is initialized as zero (pointing to the first element of the array to_do) and we increment it to go through each index of the array with i += 1. i += 1 is the Ruby way of saying "take whatever i is and add one to it."

As programmers, we end up looping through arrays quite often. We do this so often, that the designers of Ruby have created a method allowing us to iterate through items in an array without having to keep track of the index. This method is called the each method.

puts "My To Do list:"
to_do = ["buy soy milk", "learn about arrays", "learn ruby"]

to_do.each do |item|
  print " * "
  puts item
end

This is the "Ruby way" of iterating through an array, and is preferred over the previous example. Let's go over what is happening here:

The first time through the each loop, item is assigned to the string "buy soy milk". We print out an asterisk, to represent a bullet point, and then we use the puts method to print out the value of item, which is the string "buy soy milk". puts is different than print in that puts prints out a new line at the end of the string.

The next time through the each loop, item is assigned to the string "learn about arrays". We print out an asterisk, and then puts the value stored in item, which is"learn about arrays".

The third and final time through the each loop, item is assigned to the string "learn ruby". We print out an asterisk, and then puts the value stored in item, which is "learn ruby".

You will use the each method a lot when dealing with arrays. Make sure to commit this method to memory.

Outro

Here, we mostly dealt with strings as the items in our array, but our array can hold most anything. Be it integers, real numbers, File objects, or even other arrays, the Array class can handle it.

Oh, and one more thing:

pry(main)> to_do.delete("learn about arrays")