Ruby Enumerable Basics: Misusing .select and .map
We are coding in Ruby, and we are looking at two different arrays, let’s call them array1 and array2. If we want to return a new array that includes all of the elements within array1 that matches an element within array2, we could write something like this:

If we enter the following arrays as array1 and array2 into the code above, we would have a correctly functioning matching array:

Note that the match_array will order itself based upon the order of the first array (array1). In the cities example, since cities_array1 has “San Francisco” before “New Orleans”, the Ruby sequence will first look at “San Francisco” to find and push its matching value into the match_array. If you flip the array values, you will flip the element order of match_array:

We are able to take two arrays and find their matching elements! However, there may be another, more preferred way, to accomplish our task. In many professions, putting more tangible inputs into your product often yields a better result. A textbook that contains more useful tidbits such as examples, rules, and exceptions will probably be preferred to a simple textbook that only displays the rules. Tomato sauce is often more palatable when it is cooked with spices and herbs. In coding, however, less can often be more. That is, coders who put in more lines of code will, more often than not, yield a worse result. Specifically, more lines of code can take a longer time to review and have a greater chance of possessing errors.
So how can we produce fewer lines of code to achieve our desired result? Luckily for us, Ruby has Enumerables. What is an Enumerable? An Enumerable in Ruby will take an array, hash, or range and perform a specified operation on each of the individual elements within that array, hash, or range. In the case of our array, an Enumerable will do this:

for us! Ruby even has an all-encompassing list of Enumerables, with different Enumerables performing different methods.
So which Enumerable could potentially help us with our goal of finding matching elements between two arrays?
There is an Enumerable that is so important that it has 3 different names that are considered aliases:
select
filter
find_all
Select, filter, or find_all — it doesn’t matter which one you call upon in Ruby, they all perform the same action.
Going forward, this article will call on the .select method. But, again, .select can be switched with .filter or .find_all if that is your preferred method — they all behave the same way while being used in Ruby.
So what is the .select method? As mentioned in the Ruby-doc.org website:

In the first example, the .find_all method is taking in a range of numbers from 1 to 10 and finding all of the numbers that, when divided by 3, return a remainder of 0 — thus the matching [3, 6, 9] array.
In the second example, the .select method is taking in an array of numbers and selecting all of the even numbers, thus the [2, 4] array.
In the third example, the .filter method is looking for any elements that equal :foo. Thus the [:foo] array.
So how can we use .select to find our matching elements between array1 and array2? We’re going to have to use array1.select or array2.select, but it doesn’t quite add up:

Let’s take a more careful look at the examples in the ruby-doc.org website. Each example has an array or range on which it is performing the .select process ((1..10).find_all, [1,2,3,4,5].select, [:foo, :bar].filter) but, within the Enumerable, the matching operation involves a condition (i % 3 == 0, num.even?, x == :foo). In our case, the matching operation doesn’t only involve two arrays, it involves matching the individual elements of both arrays (array1 and array2). Since we are going to be operating on the elements of two arrays, we are going to need a second Enumerable.
Enter .map (or .collect, which is an alias of .map). The .map (or .collect) Enumerable will perform an operation on each element of the array and will return a new array that contains those changes.

Okay, we are considering using .map and .select on our array1 and array2. But how? To figure that out, we should go back to our original working code. It appears that the act of our finding or selecting matches is occurring here:

And the operation of choosing the elements that will be placed in the method of selecting matches occurs here:

So it appears that array1 will use .map and array2 will use .select
Alright, then let’s try:

on our exampes for array1 and array2 and see what they yield:

Oh no! We were able to use .select and .map to identify the matching array elements, but what happened? Well, I ignored the true property of .map. The .map Enumerable will take in an array and return that array with its transformed elements. The .select method correctly identified the matching array elements, but the .select method transformed the non-matching array elements into an empty array []. Also, our .map and .select method did not return one array of matching elements: [“San Francisco”, “New Orleans”]. Our .map and .select method instead returned an array of arrays: [[], [“San Francisco”], [], [“New Orleans”]] so even if we were to use an Enumerable such as .reject to remove the [] elements, we would still have to add more lines of code to solve our problem.
So what do we do?
Sometimes, we can resort to using .each. The .each Enumerable is like the .map Enumerable since it will perform an operation on each element of the array. However, .each is different than .map in that it will not return a new array that contains those changes. The .each Enumerable will instead return the same array it initially began with. In coding, it is considered less desirable to use .each when you can instead use .map. Take our .map example earlier, compared to using .each.

While using .each, we have to create an empty array, new_array, and push the transformed elements into that new_array. In this case, using .each is creating more work for us than simply using .map.
But let’s return to the solution to our initial problem, finding matching elements between two arrays:

There may very well be a better method out there that accomplishes this same goal while using different Enumerables. But, based on this solution, our best bet is to use .each so we can push our matching elements into a match_array.

Which will yield our desired result:
