![enumerating_enumerable Enumerating Enumerable](http://globalnerdy.com/wordpress/wp-content/uploads/2008/06/enumerating_enumerable.jpg)
Ten installments already? That’s right, this is the tenth Enumerating Enumerable article. As I’m fond of repeating, this is my little contribution to the Ruby community: a series of articles where I attempt to do a better job at documenting Ruby’s Enumerable
module than Ruby-Doc.org does, with pretty pictures and more in-depth examples!
In this article, I’m going to cover each_slice
, 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
- each_cons
Enumerable#each_slice Quick Summary
![Graphic representation of the "each_slice" method in Ruby's "Enumerable" module Graphic representation of the "each_slice" method in Ruby's "Enumerable" module](http://globalnerdy.com/wordpress/wp-content/uploads/2008/07/ruby_enumerableeach_slice_2.jpg)
In the simplest possible terms |
Given a number n, split the array into n-element slices (if the number of elements in the array isn’t evenly divisible by n, just put the remaining elements in the last slice), then iterate through those slices. |
Ruby version |
1.9 only |
Expects |
- A number n describing the size of the iteration slice.
- An optional block to receive the values from each iteration.
|
Returns |
nil , if used with a block.
- An
Enumerator object that outputs n-sized slices of the collection, if used without a block.
|
RubyDoc.org’s entry |
Enumerable#each_slice |
Enumerable#each_slice and Arrays
When used on an array with a block, each_slice
takes a numeric argument n and splits the array into slices of length n (if the number of elements in the array isn’t evenly divisible by n, the remaining elements are put into the last slice). each_slice
then iterates through the set of slices, passing each slice to the block. After the final iteration, each_slice
returns nil
.
Since this is yet another case when an showing an example makes things very clear, I’ll do just that, using the same example data I used in the article on each_cons
:
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_slice(3) {|team| p team}
=> ["Aquaman", "Batman", "Black Canary"]
["Flash", "Green Arrow", "Green Lantern"]
["Martian Manhunter", "Superman", "Vixen"]
["Wonder Woman"]
=> nil
When used on an array without a block, each_slice
takes a numeric argument n and returns an Enumerator
that outputs slices of the array when its next
method is called. Here’s an example:
teams_of_3 = justice_league.each_slice(3)
=> #<Enumerable::Enumerator:0x007fc73baa9830>
teams_of_3.next
=> ["Aquaman", "Batman", "Black Canary"]
teams_of_3.next
=> ["Flash", "Green Arrow", "Green Lantern"]
teams_of_3.next
=> ["Martian Manhunter", "Superman", "Vixen"]
teams_of_3.next
=> ["Wonder Woman"]
teams_of_3.next
=> StopIteration: iteration reached at end...
# (I'm skipping the rest of the error message)
teams_of_3.rewind
=> #<Enumerable::Enumerator:0x007fc73baa9830>
teams_of_3.next
=> ["Aquaman", "Batman", "Black Canary"]
Enumerable#each_slice and Hashes
When used on an hash with a block, each_slice
takes a numeric argument n and splits the hash into arrays of length n (if the number of elements in the array isn’t evenly divisible by n, the remaining elements are put into the last slice). Within these arrays, each hash element is represented as a two-element array, with the first element being the key and the second element being the corresponding value.
each_slice
then iterates through the set of arrays, passing each array to the block. After the final iteration, each_slice
returns nil
.
Here’s an example, using the same example data I used in the article on each_cons
:
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",
:tactical_officer=>"Worf", :chief_engineer=>"LaForge",
:chief_medical_officer=>"Crusher", :ships_counselor=>"Troi",
:annoying_ensign=>"Crusher", :attractive_ensign=>"Ro",
:expendable_crew_member=>"Smith"}
=> nil
enterprise_crew.each_slice(3) {|team| p team}
=> [[: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"]]
=> nil
When used on a hash without a block, each_slice
takes a numeric argument n and returns an Enumerator
that outputs arrays when its next
method is called. Here’s an example:
away_teams_of_3 = enterprise_crew.each_slice(3)
=> #<Enumerable::Enumerator:0x007fc73ba44c50>
away_teams_of_3.next
=> [[:captain, "Picard"], [:first_officer, "Riker"], [:science_officer, "Data"]]
away_teams_of_3.next
=> [[:tactical_officer, "Worf"], [:chief_engineer, "LaForge"], [:chief_medical_officer, "Crusher"]]
away_teams_of_3.next
=> [[:ships_counselor, "Troi"], [:annoying_ensign, "Crusher"], [:attractive_ensign, "Ro"]]
away_teams_of_3.next
=> [[:expendable_crew_member, "Smith"]]
away_teams_of_3.next
=> StopIteration: iteration reached at end...
# (I'm skipping the rest of the error message)
away_teams_of_3.rewind
=> #
away_teams_of_3.next
=> [[:captain, "Picard"], [:first_officer, "Riker"], [:science_officer, "Data"]]