Features

Features > Ruby Features > Rails

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 […]

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. You can follow along by typing these code samples into the Try Ruby website. 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:

  • The variable vitamin inside the “goalposts” refers to each item in the array as it goes through the loop. You can give this any name you want, but make it memorable.
  • The do and end identify a block of code that will be executed for each item. Blocks are used extensively in Ruby.
  • The #{vitamin} inside the double-quotes is how you insert a variable inside a string. There are other ways to do it, but #{} is the simplest.

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:

  • We start with an array of database row objects, as seen earlier.
  • Inject takes an argument, which in this case is a number. This is the starting value that will be manipulated during each iteration of the block and returned at the end. We could have started with a blank array ([]), a blank hash ({}), or even an existing object.
  • The arguments to the block are the variable we just initialized, and a single element from the array.

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!

The Future of Web Design is back in New York, 3-4 Nov, bringing you our fresh blend of amazing speakers, great advice and tons of networking potential. Use our special code FOWD/Vitamin to get a 15% discount!

34 Responses to “The Basics of Ruby Arrays”

  1. Ben Askins says

    Great article. I’d heard map and inject mentioned in passing but hadn’t had an opportunity to get to know them yet. Very powerful tools for the utility belt.

  2. Ben Askins says

    That’s “heard about…” - oops!

  3. kemuri says

    Great tutorial, thanx!

  4. RSL says

    Nice article. I was just reading the backside of the Pickaxe [Programming Ruby, to non-Rubyists] and was fascinated by the amount of really cool methods for Array and many other basic object types. Map is currently my favorite as it’s been saving me quite a few lines in a project I’m working on.

  5. Geoff says

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

    The += is misleading here - inject takes the return value of the block, not the current value of the variable that was passed in.

    e.g.

    FooBar = Struct.new(’FooBar’, :foo, :bar)
    list = [
    FooBar.new(’foo’, 2),
    FooBar.new(’foo’, 3),
    FooBar.new(’bar’, 1),
    FooBar.new(’bar’, 7)
    ]

    dict = list.inject(Hash.new) do |hash, foobar|
    hash[foobar.foo] ||= []
    hash[foobar.foo]

  6. picture of Geoff Grosenbach topfunky says

    You’re right…the += is unnecessary. The return value of the block is used as the sum the next time around.

    So it could just be written as sum + stat.visit_count.

    I’ll mention this in the next article since you can also use hashes inside inject by using the merge method.

  7. Robertas Aganauskas says

    Great tutorial!
    While I was able to understand how inject works before, this time I really “got” it. Code of my current project was reduced quite a bit. =)

    Thanks

  8. Prashant says

    Great tutorial!

    Looks like using arrays on Ruby is way easier than on any other language. I think it would have been a good idea if you spoke about multi-dimensional arrays since they’re also used a lot.

  9. András Tarsoly says

    Nice article, if you coming from a tranditional web developer background, the concepts behind Ruby sometimes can be hard to get a grip on.

    Well appreciated.

  10. neil says

    For handling multi-dimensional arrays (& hashes) check out http://bigbold.com/snippets/ under Ruby!

  11. RudyTalk » Blog Archive » Give ruby a shot says

    […] Simple Tutorial […]

  12. cbmeeks says

    Nice article. I’ve been wondering if Rails was something I should get into? Would rapid web app development be a fair judgement of Rails?

    cbmeeks
    http://www.codershangout.com

  13. David J. says

    Thanks for mentioning inject. I was browsing the Pick Axe for methods available on Array objects and overlooked inject at first.

    And I second the comment about the “+=” being misleading. Good catch by the readers. It might be nice to see the original code fixed, but then the comments would be out of sync.

    Call me a quantitive junky, but seeing Inject immediately makes me want to jump in and do statistical calculations! I just saw that Ruby has a wrapper GNU scientific library called ruby-gsl. http://ruby-gsl.sourceforge.net/

  14. RubyOnRailsSite.com» Blog Archive » The Basics of Ruby Arrays says

    […] Visit Site […]

  15. Grüner Tee says

    Nice article

    Grüner Tee

  16. Jeremy says

    Ruby on Rails is awesome, thanks for the tutorial. I’ve got a stack of ruby on rails books at my desk, and have hacked a fair bit of code, but never quite read enough to figre out how to form an array. Previously, I was hacking at Perl, but RoR seems like a cleaner, simpler approach, once you get all the fundamentals (like arrays) sorted.

    Looking forward to the next article in the series, if I may suggest one on the Gruff module, Ferret search, or mongrel webserver, that’d be one I’d love to read.

  17. sreeks says

    Iam a ruby newbie. Had been searching for a method to print index values in an array. This tutorial saved my day. Thanks

  18. Seth says

    nice, there are no much ruby tutoriales. keep posting’em!

  19. Manipulating structured and data in Ruby at The Minor Threat says

    […] P.S. another helpful article on Ruby Arrays is “The Basics of Ruby Array” over at the excellent Vitamin Magazine. I think I’m going to compile a nice list of Ruby resources in the future and post it once I’ve collected enough. […]

  20. atm frame relay says

    atm frame relay…

    Description of atm frame relay….

  21. Rebecca’s Ramblings » Blog Archive » Quick tip: ruby’s inject method says

    […] For more details, see this article on ruby arrays on thinkvitamin.com. […]

  22. Fernstudium says

    nice blog, keep it on :)

    regards paul

  23. Ikai Lan says

    Here’s a very powerful one: Array intersections:

    [1,2] & [2,3]
    => [2]

    [1,2,3,4] & [2,4,5]
    => [2,4]

  24. Studium says

    Thanks for your tutorials… A friend of mine is writing ruby-tutorials,t oo. You can visit his page here : http://www.dbnetworx.de. It is a german site, but the tutorials are written in english.

  25. chat says

    That’s great! I’m looking forward to it

  26. islam says

    tskler

  27. Marc says

    Thanks for this short tutorial in Ruby, i have started with Ruby some days ago and i got here many informations about programming, thanks for that!

  28. Fernstudium says

    Good Articel.

  29. Studium Finanzen says

    Thanks to Ruby für the good presentation of programming.

  30. Studium Verzeichnis says

    My Opinio is that programming with ruby doesn´t is easy, but the informations here are still good, so i still try on.

  31. Fernstudium says

    Sehr informativ, besonder im Hinblick auf ein IT Fernstudium

  32. Fern Studium says

    Thanks für the tutorial

  33. MisterInfo says

    very good article. Thank you.

  34. Vegetarier says

    Thank you for this helpful tutorial! Although my english isn´t that well, it was a great help for me.

    Best regards,
    Vegetarier

Leave a Reply

Basic HTML (<strong>, <em>, <a>, etc.) is allowed in your comments. Please be respectful and keep your comments on-topic. If we think you're being offensive for no reason, we'll delete your comment.

Comments RSS