Ruby Enumerators- Syntax Basics
Tags: ruby, codenewbie, tutorial, beginners
Published: 2022-06-03 22:22:38

Ruby is a fun language to learn. It's easy to use, and the syntax is straightforward and more intuitive than other programming languages. Despite this, it's capable of building vastly complex programs. 

In Ruby, almost everything is an object. All of these objects can have data and behaviors. Objects in the form of arrays and hashes can be given their own properties and actions, known as methods, that help us manipulate data and give objects the behaviors we want them to have. 
Enumerators are one type of method that give us fun and powerful ways to manage our data so we can focus on building cool things.

### Understanding Ruby Basics

According to Ruby documentation, an [enumerator]('https://ruby-doc.org/core-2.7.3/Enumerable.html') "provides collection classes with several traversal and searching methods, and with the ability to sort".
In other words, enumerators are methods that "enumerate", or go one-by-one, over every element of a collection, helping us to view, manipulate, or sort arrays and hashes.

Enumerators are chained to an array or hash using dot notation, and take a block of code as an argument that encapsulates what the enumerator is supposed to do with each element. This block is a chunk of code between curly braces {} (for simple, single-line blocks), or between "do" and "end" keywords. 
It takes one arbitrary element in the pipes || knows as a block parameter, that represents each element from the array. You can call the value in the pipes anything you want.

For example:
```
titles = books.collect do |b|
  b[:title]
end
```
or, for single-line blocks:
```
titles = books.collect {|b| b[:title]}
```

If you don't already know, here's a brief summary of what I mean by arrays and hashes:

* [Arrays]('https://ruby-doc.org/core-2.7.0/Array.html') are ordered collections of strings, numbers, booleans, or even other arrays or hashes, wrapped in square brackets and separated by commas. Every element in an array is indexed, with the first element starting at index 0, the second element at index 1, and so on.

* [Hashes]('https://ruby-doc.org/core-3.1.1/Hash.html') are collections of key: value pairs wrapped in curly brackets and separated by commas, where keys are commonly represented with ["symbols"]("https://www.rubyguides.com/2018/02/ruby-symbols/"), and values can be any data type.

### Practice For Yourself

If you'd like to follow along with the examples, make sure you have Ruby installed. Since there are several ways to install Ruby, check out the [installation guide]("https://www.ruby-lang.org/en/documentation/installation/"). Once installed, you can play with Ruby code in your command line prompt by typing `irb` and press `enter`.

This brings you to a built-in playground for running Ruby, and your prompt should look something like this:

`2.7.4 :001 >`

### Good to Know Moving Forward

Since the Ruby language was designed to be easy to understand, and is inspired by several other programming languages, many enumerators have aliases that do the exact same thing as each other. For example, "map" and "collect" are functionally equivalent. It doesn't matter which one you use, just be sure to use one or the other to be consistent in your code.

Also note that the "#" symbol before anything in Ruby isn't active code, it's just a comment that will be ignored by your computer.

Our enumerator examples will use this array of hashes I've called "hackers", with each hash containing made-up information we can play with:
```
hackers = [ 
  { 
    name: "Matt",
    favorite_food: "tacos",
    favorite_language: "Ruby",
    years_coding: 3
  },
  {
    name: "Angie",
    favorite_food: "chocolate",
    favorite_language: "JavaScript",
    years_coding: 10
  },
  {
    name: "Joey",
    favorite_food: "broccoli",
    favorite_language: "Python",
    years_coding: 6
  }
]
```

### Common Array Enumerables

1. [**EACH**]("https://apidock.com/ruby/Array/each")

The `.each` enumerator allows us to loop through items in an array.
It doesn't return anything and doesn't change the array, but allows us to loop through and act on an array.
```
names = hackers.each do |h|
  puts h[:name]}
end

# returns to the console:
# Matt
# Angie
# Joey
```

2. [**MAP or COLLECT**]("https://apidock.com/ruby/v2_5_5/Enumerable/map")

The `.map` aka `.collect` enumerator allows us to do something to every element of an array or hash.
It loops through and returns a new array based on some sort of condition or test.
Every time it goes through iteration, it replaces the element that was there before with the new element.
```
uppercased_food = hackers.map do |h|
  h[:favorite_food].upcase
end

# returns ["TACOS", "CHOCOLATE", "BROCCOLI"]
```
Note that `.map`/`.collect` doesn't change the original array, it creates a new one.

3. [**FILTER, SELECT, or FIND_ALL**]("https://apidock.com/ruby/v2_6_3/Enumerable/filter")

When you want to access every element of an array, check if it matches some criteria, and return a new array of all the values that match.
This won't let you perform any transformation of elements; it will only return the original elements based on whether a truthy or falsy value is returned from the block.
```
juniors = hackers.filter do |h|
  h[:years_coding] < 8
end

# returns the "Joey" and "Matt" hashes in an array, 
# excluding the "Angie" hash
```

4. [**FIND**]("https://apidock.com/ruby/v2_6_3/Enumerable/find")

`.find` finds first element that matches a condition.
This works just like FILTER, but only returns the first element that passes the condition or test. 
```
ruby_pro = hackers.find do |h|
  h[:favorite_language] == "Ruby"
end

# returns the "Matt" hash
```
Note that strings are case-sensitive. If `nil` was returned for you here, you might have a typo.

5. [**SUM**]("https://apidock.com/ruby/v2_6_3/Enumerable/sum")

`.sum` allows us to find the total sum of an element in an array.
```
total_years = hackers.sum {|h| h[:years_coding]}

# returns 19
```

6. [**SORT**]("https://apidock.com/ruby/v2_6_3/Enumerable/sort")

`.sort` returns a new array where all the elements have been sorted based on some criteria. This will not alter the original array.
Comparing elements in each iteration can be done using the ['Spaceship Operator']("https://stackoverflow.com/questions/827649/what-is-the-ruby-spaceship-operator") <=>, aka the combined comparison operator.
```
alphabetical = hackers.sort do |hacker1, hacker2|
  hacker1[:name] <=> hacker2[:name]
end

# returns an array in a new order, 
# starting with the "Angie" hash, followed by "Joey", 
# followed by "Matt"
```

There are many, many more enumerators you can use, but the ones just mentioned will help you in most cases. Be sure to look through [Ruby's documentation]("https://ruby-doc.org/core-2.7.3/Enumerable.html") to learn more, and practice with them on your own to get used to how they work. Always keep in mind what your enumerator will return, and remember these handy tips:

* When you want to manipulate elements in an array, use MAP
* When you want to query an array, use FIND or FILTER
* When you want to read things in an array, use EACH

Thanks for reading. Happy coding!