Level Up Your Ruby Skillz: Working With Arrays
Tags: ruby, beginners, tips, tutorial
Published: 2019-05-08 12:09:18

---
title: Level Up Your Ruby Skillz: Working With Arrays
published: true
description: A guide to some of the most useful methods for working with arrays in Ruby. 
tags: ruby, beginners, tips, #tutorial 
cover_image: https://thepracticaldev.s3.amazonaws.com/i/1piie4ifybj812oh8g3y.jpg
series: Level Up Your Ruby Skillz
---

When I first started out, there was a senior engineer that I worked with who was a wizard when it came to working with arrays. He taught me all the best tricks to writing succinct and clean code when it came to dealing with arrays. Here are the methods that I find the most useful and I think are good to have in your Ruby toolbox right from the start.
* [`each`](#each)
* [`map`](#map)
* [`flat_map`](#flat_map)
* [`select`](#select)
* [`detect`](#detect)
* [`reject`](#reject)
* [`count`](#count)
* [`partition`](#partition)
* [`with_index`](#with_index)
* [`chaining`](#chaining)

If you want to jump straight to the code without the explanations checkout the [cheatsheet](#cheatsheet) at the bottom! 

<a name="each"></a>
# [`each`](https://ruby-doc.org/core-2.6.0.preview2/Array.html#method-i-each)
Before we dive into some of the fancier methods above, we first need to start with the most basic, `each`. [`each`](https://ruby-doc.org/core-2.6.0.preview2/Array.html#method-i-each) will call a block once for every given element in an array. When it is done, it will **return the original array.** That last part is key and is easy to forget. Even those of us who have been working with Ruby for a while sometimes forget it. Here is an example. 
```ruby
result = [1, 2, 3].each do |number|
  puts 'hi'
end
```
That code will produce the following result when run in a console. NOTE: In the example below and those that follow, irb simply means I am in a Ruby console. 
```
irb:> result = [1, 2, 3].each do |number|
>   puts "hi #{number}"
> end
hi 1
hi 2
hi 3
=> [1, 2, 3]
```
For each number in our array we printed "hi" plus that number. Then, after we have finished traversing the entire array, our original array is returned.

Keep in mind, I am using the `do/end` block notation above, but you can also use the bracket syntax for your block which is shown below.
```
irb:> result = [1, 2, 3].each{|number| puts "hi #{number}"}
hi 1
hi 2
hi 3
=> [1, 2, 3]
```
As you can see, regardless of syntax, the result is the same. I am going to continue to use the `do/end` syntax throughout this guide because I think it makes the code and logic easier to understand. With that said, all of these methods will work with the bracket syntax as well.

<a name="map"></a>
# [`map`](https://ruby-doc.org/core-2.6.3/Array.html#method-i-map)

In the early days, when I was new to Ruby, every time I wanted to build an array I did something like this:
```ruby
result = []
[1, 2, 3, 4].each do |number|
  result << number + 2
end
# result = [3, 4, 5, 6]
```

I quickly learned there was a better way, and that is by using `map`. [`map`](https://ruby-doc.org/core-2.6.3/Array.html#method-i-map) returns a new array with the results of executing the block once for every element in your original array. Here is an example:
```ruby
result = [1, 2, 3, 4].map do |number|
  number + 2
end
# result = [3, 4, 5, 6]
```
We add 2 to every number in our original array and then group those results up into a new array, which is returned. Now our code is a bit cleaner and more compact.  

<a name="flat_map"></a>
# [`flat_map`](https://ruby-doc.org/core-2.6.3/Enumerable.html#method-i-flat_map)
`map` is great for collecting a set of results, but what happens when you want to map over nested arrays? That is when `flat_map` comes in handy. If you find yourself with a set of nested arrays then you might want to checkout `flat_map`. For example, say you have code like this with a couple of nested arrays.

```ruby
result = []
[1, 2, 3].each do |number|
  ['a', 'b', 'c'].each do |letter|
    result << "#{number}:#{letter}"
  end
end
# result = ["1:a", "1:b", "1:c", "2:a", "2:b", "2:c", "3:a", "3:b", "3:c"]
```
We get a single level array, which is what we wanted, but how could we tighten this up? Let's try using `map`.
```ruby
result = [1, 2, 3].map do |number|
  ['a', 'b', 'c'].map do |letter|
    "#{number}:#{letter}"
  end
end
# result = [["1:a", "1:b", "1:c"], ["2:a", "2:b", "2:c"], ["3:a", "3:b", "3:c"]]
```
Hmmm, that is not quite what we want. We want a flat, single level array and `map` is creating a nested one. In order to flatten that nested array we can use `flat_map`. 
```ruby
result = [1,2,3].flat_map do |number|
  ['a', 'b', 'c'].map do |letter|
    "#{number}:#{letter}"
  end
end
# result = ["1:a", "1:b", "1:c", "2:a", "2:b", "2:c", "3:a", "3:b", "3:c"]
```
[`flat_map`](https://ruby-doc.org/core-2.6.3/Enumerable.html#method-i-flat_map) works similar to `map` in that it collects the results from your block into an array, but as a bonus, it will flatten it. Under the hood, `flat_map` is [concatenating](https://ruby-doc.org/core-2.6.3/Array.html#method-i-concat) all of the inner arrays into a single one. Using `flat_map` returns that single level array we wanted. 

<a name="select"></a>
# [`select`](https://ruby-doc.org/core-2.6.3/Array.html#method-i-select)
Similar to the `map` example, when I was starting out, if I wanted to conditionally select elements from an array, for example, choose all the even numbers, I would do something like this:
```ruby
result = []
[1, 2, 3, 4].each do |number|
  result << number if number.even?
end
# result = [2, 4]
```
It works, but there is an even more succinct way, and that is by using `select`. [`select`](https://ruby-doc.org/core-2.6.3/Array.html#method-i-select) returns an array containing all elements for which the given block returns a true value. This means we can rewrite our above block of code like this!
```ruby
result = [1, 2, 3, 4].select do |number|
  number.even?
end
# result = [2,4]
```

<a name="detect"></a>
# [`detect`](https://ruby-doc.org/core-2.6.3/Enumerable.html#method-i-detect)
Now we are going to kick it up a notch. What if instead of wanting all the even numbers back from an array, you only want the first even number that you find? For that you can use `detect`. [`detect`](https://ruby-doc.org/core-2.6.3/Enumerable.html#method-i-detect) will return the first entry for which your block evaluates to true. So if we run a similar block of code as above, but replace `select` with `detect`, you can see we get back only the first even number. 
```ruby
result = [1, 2, 3, 4].detect do |number|
  number.even?
end
# result = 2
```
One important thing to note here is that we are now returning a number(our entry) and NOT an array.

But what happens if our block never evaluates to true? What if there are no even numbers in our array? In that case, `detect` will return nil.
```ruby
result = [1, 3, 5, 7].detect do |number|
  number.even?
end
# result = nil
```
To summarize, `detect` will return the first entry your block evaluates to true for OR it will return nil if no entry evaluates to true for your block.

<a name="reject"></a>
# [`reject`](https://ruby-doc.org/core-2.6.3/Array.html#method-i-reject)
Now let's look at the inverse of `select`, which is `reject`. [`reject`](https://ruby-doc.org/core-2.6.3/Array.html#method-i-reject) will return all entries for which your block evaluates FALSE. So instead of doing this:
```ruby
result = []
[1, 2, 3, 4].each do |number|
  result << number if !number.even?
end
# result = [1, 3]
```
We can simplify the above code and do something like this instead:
```ruby
result = [1, 2, 3, 4].reject do |number|
  number.even?
end
# result = [1, 3]
```
This time we will return each number which is not even, so those where `number.even?` returns false.

<a name="partition"></a>
# [`partition`](https://ruby-doc.org/core-2.6.3/Enumerable.html#method-i-partition)
We have just seen two ways we can filter through arrays in Ruby using `select` and `reject`. But what if you want to straight up separate your single array into two arrays, one for even numbers and one for odd numbers? One way to accomplish this is by doing:
```ruby
even = [1, 2, 3, 4].select do |number|
  number.even?
end
# even = [2, 4]
odd = [1, 2, 3, 4].reject do |number|
  number.even?
end
# odd = [1, 3]
```
But, there is an even better way, you can use `partition`! Hold on to your seats for this one. [`partition`](https://ruby-doc.org/core-2.6.3/Enumerable.html#method-i-partition) will return TWO arrays, the first containing the elements of the original array for which the block evaluated true and the second containing the rest. This means we can take what we wrote above and simplify it to: 
```ruby
result = [1, 2, 3, 4].partition do |number|
  number.even?
end
# result = [[2, 4], [1, 3]]
```
As you can see, `partition` will return two arrays, one with even numbers, and one for odd numbers. If we want to assign our `even` and `odd` variables all we have to do is
```ruby
even = result.first
odd = result.last
```
However, as you can probably guess, there is an even better way! We can eliminate that single `result` variable altogether and write something like this
```ruby
even, odd = [1, 2, 3, 4].partition do |number|
  number.even?
end
# even = [2, 4] and odd = [1, 3]
```
This syntax is going to automatically assign the first array to `even` and the second array to `odd`. You can use this array assignment syntax anytime you are dealing with nested arrays. Here is an example of how you can breakup 3 arrays.
```
irb:> a, b, c = [[1], [2], [3]]
=> [[1], [2], [3]]
irb:> a
=> [1]
irb:> b
=> [2]
irb:> c
=> [3]
```

<a name="count"></a>
# [`count`](https://ruby-doc.org/core-2.6.3/Array.html#method-i-count)
`count` for the most part is pretty self explanatory, by default, it will count the number of elements in your array.
```
irb:> [1, 1, 2, 2, 3, 3].count
=> 6
```
But, did you know it can do so much more? For starters, can pass `count` an argument. If you pass [`count`](https://ruby-doc.org/core-2.6.3/Array.html#method-i-count) an argument, it will count the number of times that argument occurs in your array. 
```
irb:> [1, 1, 2, 2, 3, 3].count(1)
=> 2
irb:> ['a', 'a', 'b', 'c'].count('c')
=> 1
```
You can also pass [`count`](https://ruby-doc.org/core-2.6.3/Array.html#method-i-count) a block!😲When passed a block, `count` will return the count for the number of entries that block evaluates to true for. 
```
irb:> [1, 1, 2, 2, 3, 3].count do |number|
  number.odd?
end
=> 4
```
Every number that is odd in our array was counted and the result returned was 4.

<a name="with_index"></a>
# [`with_index`](https://ruby-doc.org/core-2.6.0.rc1/Enumerator.html#method-i-with_index)
Last but not least, I want to talk about traversing an array with an index. Often when we want to keep track of where we are in an array of elements we will do something like this.
```
irb:> index = 0
irb:> ['a', 'b', 'c'].each do |letter|
  puts index
  index += 1
end
0
1
2
```
However, there is a better way! You can use [`with_index`](https://ruby-doc.org/core-2.6.0.rc1/Enumerator.html#method-i-with_index) with `each`, or any of the methods I listed above, to help you keep track of where you are in an array. Here are some examples of how you can use it. (REMEMBER: Array indexes start at 0 😃)
```
irb:> ['a', 'b', 'c'].each.with_index do |letter, index|
  puts index
end
0
1
2
```
In this example we are simply iterating over our array and printing out the index for each element.

```ruby
result = ['a', 'b', 'c'].map.with_index do |letter, index|
  "#{letter}:#{index}"
end
# result = ["a:0", "b:1", "c:2"]
```
In this example, we are combining the index with the letter in our array to form a new array using the `map` method.

```ruby
result = ['a', 'b', 'c'].select.with_index do |letter, index|
  index == 2
end
# result = ["c"]
```
This example is a little trickier. Here we are using our index to help us select the element in our array that is at index equal to 2. In this case, that element is "c".

<a name="chaining"></a>
# `chaining`
The last tidbit of knowledge I want to leave you with is that any of the methods above that return an array(all except `count` and `detect`), you can chain together. For these examples I am going to use bracket notation because I think it's easier to read chaining methods from left to right rather than up and down. 

For example, you can do this:
```ruby
result = [1, 2, 3, 4].map{|n| n + 2}.select{|n| n.even?}.reject{|n| n == 6}.map{|n| "hi #{n}"} 
# result = ["hi 4"]
```
Let's break down what is happening here given what we learned above. 
1) `map` is going to add 2 to each of our array elements and return `[3, 4, 5, 6]`
2) `select` will select only the even numbers from that array and return `[4, 6]` 
3) `reject` will remove any number equal to 6 which leaves us with `[4]`
4) Our final `map` will prepend "hi" to that 4 and return `["hi 4"]`

# You Made it!!!!
![](https://thepracticaldev.s3.amazonaws.com/i/0hw597r707r9a3koalyf.gif)
Congrats, you made it all the way to the end! Hopefully, you find these array methods useful as you are writing your Ruby code. If anything is unclear, PLEASE let me know in the comments. This is my first time writing a tutorial so I welcome any and all feedback 🤗

<a name="cheatsheet"></a>
If you would like all of these code examples without the lengthy explanations checkout [this cheatsheet](https://paper.dropbox.com/doc/Ruby-Array-Methods--AcuxIuoFBAtO4Q1CxBDuNrVsAg-cRF8GIgVFnC3zhfINk7Wy) that @lukewduncan graciously put together!