![enumerating_enumerable Enumerating Enumerable](http://globalnerdy.com/wordpress/wp-content/uploads/2008/06/enumerating_enumerable.jpg)
Welcome to the ninth installment of Enumerating Enumerable, the series of articles where I attempt to do a better job at documenting Ruby’s Enumerable
module than Ruby-Doc.org does.
I’m going through the Enumerable
‘s methods in alphabetical order, and we’ve reached the methods that are variations on each
In this article, I’m going to cover each_cons
, which got introduced in Ruby 1.9.
If you missed any of the earlier articles, I’ve listed them all below:
- all?
- any?
- collect / map
- count
- cycle
- detect / find
- drop
- drop_while
Enumerable#each_cons Quick Summary
![Graphic representation of the \"each_cons\" method in Ruby\'s \"Enumerable\" module Graphic representation of the \"each_cons\" method in Ruby\'s \"Enumerable\" module](http://globalnerdy.com/wordpress/wp-content/uploads/2008/07/ruby_enumerableeach_cons_2.jpg)
In the simplest possible terms |
Think of each_cons as an each that takes a number n and spits out n elements at a time. |
Ruby version |
1.9 only |
Expects |
A number n describing the number of elements to be fed to the block. |
Returns |
nil if used with a block
- An
Enumerator object that outputs n-sized consecutive array slices of the collection if used without a block.
|
RubyDoc.org’s entry |
Enumerable#each+cons |
Enumerable#each_cons and Arrays
When used on an array and given a block and a number n as an argument, each_cons
is like an each
that goes through each element in the array and outputs an n-sized array slice of the original array starting at the current element.
each_cons
is one of those methods that’s really tough to describe. This is one of those cases where a demonstrating trumps describing…
justice_league = ["Aquaman", "Batman", "Black Canary", \
"Flash", "Green Arrow", "Green Lantern", \
"Martian Manhunter", "Superman", \
"Vixen", "Wonder Woman"]
=> justice_league = ["Aquaman", "Batman", "Black Canary", "Flash", "Green Arrow",
"Green Lantern", "Martian Manhunter", "Superman", "Vixen", "Wonder Woman"]
justice_league.each_cons(3) {|team| p team}
=> ["Aquaman", "Batman", "Black Canary"]
["Batman", "Black Canary", "Flash"]
["Black Canary", "Flash", "Green Arrow"]
["Flash", "Green Arrow", "Green Lantern"]
["Green Arrow", "Green Lantern", "Martian Manhunter"]
["Green Lantern", "Martian Manhunter", "Superman"]
["Martian Manhunter", "Superman", "Vixen"]
["Superman", "Vixen", "Wonder Woman"]
=> nil
Note that in this case, each_cons
returns nil
.
each_cons
can also be used without providing a block. In this case, you’re using it to create an Enumerator
object that you can then use to spit out array slices when you call its next
method:
# Let's create an enumerator that we can use to give us three-person
# superhero teams
teams_of_3 = justice_league.each_cons(3)
=> #
# Let's get the first team of 3
teams_of_3.next
=> ["Aquaman", "Batman", "Black Canary"]
# Now the next one...
teams_of_3.next
=> ["Batman", "Black Canary", "Flash"]
teams_of_3.next
=> ["Black Canary", "Flash", "Green Arrow"]
teams_of_3.next
=> ["Flash", "Green Arrow", "Green Lantern"]
# Let's go back to the first team of 3
teams_of_3.rewind
=> #
teams_of_3.next
=> ["Aquaman", "Batman", "Black Canary"]
Enumerable#each_cons and Hashes
When used on a hash and given a block and a number n as an argument, each_cons
is like an each
that goes through each element in the array and outputs an n-sized array slice of the hash starting at the current element. Note that in the process, hash elements are converted into two-element arrays where the first element contains the key and the second element contains the corresponding value.
Again, examples speak louder than descriptions:
enterprise_crew = {:captain => "Picard",
:first_officer => "Riker",
:science_officer => "Data",
:tactical_officer => "Worf",
:chief_engineer => "LaForge",
:chief_medical_officer => "Crusher",
:ships_counselor => "Troi",
:annoying_ensign => "Crusher",
:attractive_ensign => "Ro",
:expendable_crew_member => "Smith"}
=> {:captain=>"Picard", :first_officer=>"Riker", :science_officer=>"Data", :tact
ical_officer=>"Worf", :chief_engineer=>"LaForge", :chief_medical_officer=>"Crush
er", :ships_counselor=>"Troi", :annoying_ensign=>"Crusher", :attractive_ensign=>
"Ro", :expendable_crew_member=>"Smith"}
enterprise_crew.each_cons(3) {|team| p team}
=> [[:captain, "Picard"], [:first_officer, "Riker"], [:science_officer, "Data"]]
[[:first_officer, "Riker"], [:science_officer, "Data"], [:tactical_officer, "Worf"]]
[[:science_officer, "Data"], [:tactical_officer, "Worf"], [:chief_engineer, "LaForge"]]
[[:tactical_officer, "Worf"], [:chief_engineer, "LaForge"], [:chief_medical_officer, "Crusher"]]
[[:chief_engineer, "LaForge"], [:chief_medical_officer, "Crusher"], [:ships_counselor, "Troi"]]
[[:chief_medical_officer, "Crusher"], [:ships_counselor, "Troi"], [:annoying_ensign, "Crusher"]]
[[:ships_counselor, "Troi"], [:annoying_ensign, "Crusher"], [:attractive_ensign, "Ro"]]
[[:annoying_ensign, "Crusher"], [:attractive_ensign, "Ro"], [:expendable_crew_member, "Smith"]]
=> nil
As with arrays, each_cons
, when used on a hash, returns nil
.
Again, as with arrays, each_cons
can also be used without providing a block to create an Enumerator
:
# Starfleet has decided to let the ship's computer determine
# the away teams, which are groups of 3
away_teams_of_3 = enterprise_crew.each_cons(3)
=> #
# Okay, who's the first away team?
away_teams_of_3.next
=> [[:captain, "Picard"], [:first_officer, "Riker"], [:science_officer, "Data"]]
# Let's get the next one
away_teams_of_3.next
=> [[:first_officer, "Riker"], [:science_officer, "Data"],
[:tactical_officer, "Worf"]]
away_teams_of_3.next
=> [[:science_officer, "Data"], [:tactical_officer, "Worf"],
[:chief_engineer, "LaForge"]]
# Let's go back to the first away team
away_teams_of_3.rewind
=> #
away_teams_of_3.next
=> [[:captain, "Picard"], [:first_officer, "Riker"], [:science_officer, "Data"]]