Strategies for Looping Through Collections in Ruby (Part 1: Map/Collect)
Firstly, I’d like to apologize to (what I assume) is my massive audience for my lack of blog posts over these past few months. As it turns out, learning and reading about code tends to take much more of a priority than actually writing about what I’ve learned, but alas, here I am.
This three-part series I plan to write is meant to serve as a simple summary of three(ish) enumerator class methods that I often come across when dealing with and manipulating collections (mostly arrays, but sometimes hashes) in Ruby. The three methods are Map(or Collect), Select (conversely, Reject), and Reduce (or Inject). These enumerator methods seem to be the most widely used when manipulating collections, and are thus important in any fundamental understanding of Ruby. Broadly speaking, the Map function manipulates elements of a collection based on given block parameters; the Select function “filters” a collection based on block parameters, and returns a new array based on these filters; the Reduce method returns a new value that combines elements of a collection based on block parameters. And just to be clear, when I say “block parameters”, I mean this:
{|item| block }Where the "item" refers to each element of the collection, and the "block" is the what is actually "being done" to each element in the array
This post is about the Map and Collect methods. I will give some examples of how these methods can be used, but first, let’s start off with some arrays to manipulate:
Got it? Alrighty, let’s begin with some basic code:
This is pretty straightforward stuff. |x|
is the block parameter or block variable, and it represents each element in the array on the given “loop” through the array. |x|
can be anything the programmer wants to call it; I’m using “x” for brevity’s sake, but again, I could replace |x|
with |supercalifragilisticexpialidocious|
, and still work the exact same way (although this would technically make the program run slightly slower). In my example, |X|
is equal to “a” on the first iteration, “b” on the second, etc. The block argument that is being passed to each element is x + ‘b’
; thus, each iteration through the array will add the string “b” to the element. The resulting new(this is important! The original array array is NOT being altered!) array is [“ab”, “bb”, “cb”, “db”]
.
Pretty straightforward stuff, right? Let’s move on to another example:
In this example, we’re manipulating two different arrays- one that contains only integer class elements (number_array), and one that contains only strings of numbers (number_as_string_array). The map method block being called on these two arrays are identical, but as we can expect, the resulting new array for each of these will be different. The first example uses simple math by multiplying each integer in the array by 2; the second example uses “string math”(I made that up) to print out each string element twice. “String math” is not the same as “number math”; for example, adding and subtracting an integer to/from a string will result in an error. Only the * operator will effectively combine a string and a non-string number (integer, float, etc.)
Again, pretty straightforward. Here is a further use of the map method that combines the with_index method:
This is pretty cool. In this example, the block takes two block parameters: x and i, where “x” represents an element of the array, and “i” represents the index value of the array (i.e. at “a”, i=0, at “b”, i=1, at “c”, i=2, etc.). Thus, in each iteration, this method is multiplying the string value of the element (“a”, “b”, “c”, or “d”) by it’s index value. Thus, “a”*0 => “”(empty string), “b”*1 => “b”, etc.
Finally (and now we’re getting fancy!), we can do some cool stuff with arrays of strings using the following syntax:
This is some cool little shorthand that allows the programmer to basically combine two methods: one that is being called on the array (in this case, map or collect), with a string method (in this case, capitalize or length). So what’s being done here? The map/collect methods are iterating through the array, and the length and capitalize methods are being called on each string element in the array. This can also be done using integer/float/decimal class methods, assuming the array is comprised of those types of elements.
A Quick Note on Bang! Methods:
So that’s that! A brief introduction to the map/collect methods. As a final note, I will add this: the bang(!) “method” can be added to the end of map or collect (e.g. word_array.map!), but be wary! This bang-method is unique in that it actually changes the original array to the new one as specified in the block argument. In all these previous examples, a new “copy” of the array was created, leaving the original array unchanged. The bang! method will erase and update the original array. This can be a somewhat risky thing to do, especially if that array that is being manipulated with the bang! method is also being referenced elsewhere in a block of code. I would therefore say to use the bang! method sparingly and wisely.
See you next time for Select and Reject!