Rails - core extensions - Array

I can still remember the early days I decided to learn Rails. A lot of new concepts, conventions and “magic” things were daily presented to me. It also brings to my memory the time that I spent a whole afternoon dealing with my custom helpers methods to handle Array grouping and displaying operations. Well, this event happened some time ago, but is not rare to see nowadays, pieces of code, including gems, defining its own methods to solve problems that were already solved.

Rails does a lot of work to make our life easier. It includes the extention of Ruby core built-in classes, like Hash, Array, etc. Sometimes we spend a considerable amount of time trying to solve a problem that was already solved.

This post will share the Array extension methods that Rails defines that I am used to use when I am working (to see a complete list of extensions, browse Rails documentation or its source code).

from / to

There is times when You have to get Array elements from/to a defined point. Let’s say you have the following array:

> list = [:apple, :banana, :chocolate, :milk, :cow, :singer, :vim]

And lets imagine that You want to get all the elements from index 5th position to the end. You could use the following code to get it done:

> list[5..-1]
=> [:singer, :vim]

And that’s OK, it would work perfectly, but Rails defines a method named “from” that does the same:

> list.from(5)
=> [:singer, :vim]

You can use the same approach to get elements from the beginning to a defined point. Let’s say now you want to get all the element til the 2nd position (elements 0, 1 and 2). You can the following code to do that:

> list[0..2]
=> [:apple, :banana, :chocolate]

Same as above, you have a method to it, named “to”:

> list.to(2)
=> [:apple, :banana, :chocolate]

first / last / second /third / fourth / fifth / forty_two

There is times when you want to get a specific element in an array. You may want to get the first or the last element and use the conventional indexation to get them, just like:

> list = ["Paul", "Matthew", "John", "Peter", "Luke"]

The first element of the array:

> list[0]
=> "Paul"

The last element of the array:

> list[-1]
=> "Luke"

And that works really well, but what about using some already defined methods that help you getting the same behavior and also make your code cleaner? Then you can use “first” and “last” methods to get the same behavior:

The first element of the array:

> list.first
=> "Paul"

The last element of the array:

> list.last
=> "Luke"

You have also the methods “second”, “third”, “fourth”, “fifth” and “forty_two” that are self-explanatory. You may think that’s already known by people using Rails, but based in what I have seen, I am going to disagree with you.

to_sentence

Using the same array:

> list = ["Paul", "Matthew", "John", "Peter", "Luke"]

Sometimes you have to display the items in a human-style list. So, you could maybe use the following code to create this behavior:

> last = list.pop
=> "Luke"

> list.join(", ") + [" and ", last].join
=> "Paul, Matthew, John, Peter and Luke"

You’ve just created a sentence built from the array elements. But this problem is really common and not surprisingly, Rails defines a way to do it, using the “to_sentence” method:

> list.to_sentence
=> "Paul, Matthew, John, Peter and Luke"

in_groups_of

One of the things that I am always using, is breaking arrays into a grouping organization. I have seen lots of different implementations to solve this problem, including my own solutions (in my early Rails experiments). Let’s use the following array:

> list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

What would you do if you wanted to group those elements in groups of 2 elements? Maybe you are wondering about a fancy combination about map, zip, collect, but for now we are going to use the “in_groups_of” method, just like:

> list.in_groups_of(2)
=> [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]

now you have your Array elements organized in groups of 2 elements. What if you want to have groups of 3 elements?

> list.in_groups_of(3)
=> [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, nil, nil]]

Rails tries to fit everything, but as it was not able to get enough elements to create the latest group, then it fills with nil value. But you can override it, defining what you want to use to fill the empty spots:

> list.in_groups_of(3, 0)
=> [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 0, 0]]

or maybe you want just get rid of them, so let’s do it:

> list.in_groups_of(3, false)
=> [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]

in_groups

Using in_groups_of you can define the number of elements inside a group you want to create. But what happens when you want to create a specific number of groups (not the # of elements inside it) ? Well, for those times, you have the “in_groups” method. Let’s use the same array used in the example above:

> list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

And let’s create 3 groups with those elements:

> list.in_groups(3)
=> [[1, 2, 3, 4], [5, 6, 7, nil], [8, 9, 10, nil]]

And you can define the default element to fit the nil spots:

> list.in_groups(3, "empty")
=> [[1, 2, 3, 4], [5, 6, 7, "empty"], [8, 9, 10, "empty"]]

Or completely take the elements that don’t fit away:

> list.in_groups(3, false)
=> [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]

sample

Have you ever needed to get random elements of an array? Well, I think everyone had already to do something like it. Aiming to get it done, you maybe created code like:

> list.sort_by { rand }.slice(0, 3)
=> [4, 7, 9]
> list.shuffle.slice(0, 3)
=> [9, 10, 4]

And they really work. But there is a simple way, using the “sample” method:

> list.sample(3)
=> [10, 5, 2]

The idea behind this post is a personal "reflection" about Rails extensions to built-in Ruby classes that I usually use, not being "the list of right things" to use. It's based on my experience and needs.

You might also like

SinatraSimpleRouter

I am open sourcing a project that I have been using a lot lately. You can easily define routes and some rules...

Comparison between Rack, Sinatra and Webmachine

Benchmarking Ruby and Erlang

Healthyr - Rails app performance monitor

Open sourcing a lib I created to benchmark Rails apps, using ActiveSupport::Notifications

Download free e-book

Learn different strategies on API versioning with "Versioned APIs with Phoenix" free e-book