Site icon Treehouse Blog

The Foundations of Ruby Arrays

An array is a list of items in order (like vitamins, minerals, and chocolates).

Those keeping score at home might be interested to know that the Rails website framework makes 771 calls to Array.each, 558 calls to Array.map, and 1,521 calls to Array.empty?, not to mention the 2,103 times it accesses a single element inside an array.

But these are just numbers. How do you use arrays in Ruby?

Creating Arrays

Most of the time, you will be working with arrays of database objects. Other times, you will need to make a simple array of your own.

If you have used Perl, PHP, Python, or other scripting languages, the syntax of Ruby might seem at least remotely familiar to you. If you have installed Ruby on your computer, you can also use the “irb” command-line program, which runs lines of code interactively.

You can make an array by using square brackets like this:

# Make a list of clues for a game of charades
clues = ['vitamins', 'minerals', 'chocolates']

# Create the same array by splitting on whitespace
clues = %w(vitamins minerals chocolates)

# Create the same array in steps
clues = Array.new
clues << 'vitamins'
clues << 'minerals'
clues << 'chocolates'

You can retrieve values from an array by number, starting at zero. In these examples I’ll use => to show the result of each line.

a_clue = clues[0]
=> 'vitamins'

another_clue = clues[1]
=> 'minerals'

Ruby also has some shortcuts for commonly accessed attributes of an array:

a_clue = clues.first
=> 'vitamins'

another_clue = clues.last
=> 'chocolates'

clues.length
=> 3

Ok … enough of the basics. What can you do with an array?

each and each_with_index

Many languages force you to handle arrays with arcane sequences of semicolons, parentheses, and placeholders. Not Ruby!

my_vitamins = ['b-12', 'c', 'riboflavin']

my_vitamins.each do |vitamin|
  puts "#{vitamin} is tasty!"
end
=> b-12 is tasty!
=> c is tasty!
=> riboflavin is tasty!

As you might guess, this prints a message for each of the vitamins. Here are a few things to remember:

What if we wanted to print the name of the vitamin and also do something with its place in the array?

my_vitamins.each_with_index do |vitamin, index|
  puts "#{index} cheers for #{vitamin}!"
end
=> 0 cheers for b-12!
=> 1 cheers for c!
=> 2 cheers for riboflavin!

Again, the names “vitamin” and “index” inside the vertical bars are names that you choose. However, the “each_with_index” method calls the block with two values, so you need to provide two variable names. Several useful references can be found at Ruby-Doc.org.

If this were production code, we might write an additional method to apply proper English grammar based on the number of cheers (Rails has such a method that we could use). We might also want to use a more authoritative source for determining how many cheers each vitamin should get!

map

Ruby’s ability to work with arrays doesn’t stop there. Array.map calls a block for each item and returns a new array based on the result of the block.

nouns = ['truffle', 'kiss', 'rabbit']
array_of_chocolates = nouns.map do |noun|
  "chocolate #{noun}"
end
# array_of_chocolates now has these values
=> ['chocolate truffle', 'chocolate kiss', 'chocolate rabbit']

You might notice that we don’t have to use the “return” keyword … Ruby automatically returns the last value in a block. In this case, the return value from each iteration of the block is the new “chocolate something” string. However, we could have returned a number or any other kind of object.

On my blog I’m writing a Rails plugin to take data from my Mint stats installation and show a list of popular pages. I use “map” to put the numbers together.

# Get an array of rows from a database query
stats = Mint.popular_pages

# Assemble a summary for each
stats_report = stats.map do |stat|
  "#{stat.resource_title} was visited #{stat.visit_count} times"
end
# stats_report is now an array with these values:
=> ['Home was visited 1200 times', 'Search was visited 900 times', ...]

The resource_title and visit_count methods are actually fields in the database. ActiveRecord looks at the database schema and creates these methods automatically. I use these to build a string for each row which is returned as a new array.

inject

The inject method is one of my favorites even though it is a bit complicated (Ruby borrowed it from the Smalltalk language). Let’s look at an example and then I’ll explain how it works:

# Get an array of rows from a database query
stats = Mint.popular_pages

# Add statistics to get total number of visits
total_visits = stats.inject(0) do |sum, stat|
  sum  = stat.visit_count
end
=> 8800

Several things are happening here:

Still confused? That’s ok … let’s step through it.

To begin with, “sum” will be zero because we sent “0” as the initializing value to inject.

“stat” will be the first item from the “stats” array. We add that page’s number of visits to the current “sum”.

That cycle repeats for all the elements in the array, gradually increasing the overall “sum”.

At the end, the final value of “sum” is returned (8,800 in this case).

So that’s a lot of functionality in a very small amount of code. In fact, you could fit it all on a single line with the optional curly-bracket syntax:

total_visits = stats.inject(0) {|sum, stat| sum  = stat.visit_count}

Operators – and

Arrays are capable of much more, but here is a final feature: addition and subtraction. Adding arrays simply combines them, even if there are duplicates. Array subtraction is smart enough to take out the duplicates.

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

a - b
=> [2, 3]

a   b
=> [1, 2, 3, 1, 4, 5]

(a   b) - a
=> [4, 5]

Many of these methods are available to any object that has its own “each” method! See Ruby-Doc or the older online version of Programming Ruby for the details.

And tune in next time for the basics of Ruby hashes!

Exit mobile version