HENRY'S BLOG

Enumerable_

#map

í
Enumerable#map
First of all, what is Enumerable?
The Enumerable mixin provides collection classes with several traversal and searching methods, and with the ability to sort. I won't go further into what a mixin is, but you can think of it as a class which contains a combination of methods from other classes for now. If you understand loops and arrays and hashes, there's nothing new here. But you can do more with less lines of code, using the Enumerable mixin.

Take a look at this code:
  1. arr = [1, 2, 3, 4, 5]
  2. arr.each_index do |i|
  3.   arr[i] *= 10
  4. end

  5. puts arr.join(", ") # => 10, 20, 30, 40, 50
It takes an array and multiplies each element with 10.
Now, #map is a method returning a copy of the its invoking collection. That means that not the actual array is modified, but instead you can assign #map's return to a new array. Here's how it looks like:
  1. arr = [1, 2, 3, 4, 5]
  2. new_arr = arr.map { |x| x * 10 }

  3. puts arr.join(", ")     # => 1, 2, 3, 4, 5
  4. puts new_arr.join(", ") # => 10, 20, 30, 40, 50
As you can see, arr hasn't changed! Instead, the modified values have been assigned to new_arr!
So #map is just some fancy fork of each! In fact, #map, and all the other Enumerable iterating methods are based off of each!
If you wanted to actually change arr, you could also use arr.map!{|a| a * 10} (notice the exclamation mark!).

#group_by

ì í
Enumerable#group_by
#group_by groups the collection by result of the { BLOCK }. It returns a hash where the keys are the evaluated result from the block and the values are arrays of elements in the collection that correspond to the key. Let's have a look at an example:
  1. array = ["Spiderman", "Batman", "Superman", "Hulk", "Magneto"]
  2. hash = array.group_by { |i| i.include?("e") }

  3. puts(hash.map{|k,v| "#{k} = #{v}"}.join(', '))
    # => true = ["Spiderman", "Superman", "Magneto"], false = ["Batman", "Hulk"]
(Don't get confused by the last line, it just prints out the hash in a readable way.)
This code takes an array of names and divides the array in two groups: one group for which it holds true that all its elements contain an "e", and one group for which this is false. The reason why it's exactly two groups here is that include? only returns either true or false. But of course you can put other statements into the block and hence have more (or less) than two groups.
So the "workflow" of this little program looks like this:
  1. Take [i]th element of array and check whether it include?s an "e".
    - So it takes "Spiderman" and evaluates "true" for it, because the string contains an "e". The key "true" gets created, with the value ["Spiderman"] (-> array).
  2. Repeat step 1 for all elements in the collection.
  3. Print out the result.
    - Now a hash with two keys ("true" and "false") with corresponding two arrays, where one array holds the elements ["Spiderman", "Superman", "Magneto"] (key "true") and the other holds the elements ["Batman", "Hulk"] (key "false"), has been printed.

#cycle

ì í
Enumerable#cycle
#cycle (n) calls what's stated in { BLOCK } for each element of an enum (we'll use a string array in this case) repeatedly. It repeats n times. If no arguments or nil are passed, the method doesn't stop cycling until the user breaks the program from outside. If a non-positive number is given or the collection is empty, the method does nothing. It just returns nil if the loop has finished without getting interrupted, and not some new enum (array). Let's have a look at an example:
  1. milessong = ["But I would walk 500 miles",
  2. "And I would walk 500 more",
  3. "Just to be the man who walked 1,000 miles",
  4. "To fall down at your door", ""]

  5. milessong.cycle(500) { |x| puts x }
    # => 500x the milessong!
This code prints out 500x the refrain of Proclaimers' - 500 Miles 10 HOURS! It takes every element of the array milessong, puts it, and repeats this procedure 500 times.
I have to admit that I don't see many usecases for this, but at least you can do it!! ;-)