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:
Enumerable#each_slice Quick Summary
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 |
|
Returns |
|
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
:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
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
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
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 => #<Enumerable::Enumerator:0x007fc73ba44c50> away_teams_of_3.next => [[:captain, "Picard"], [:first_officer, "Riker"], [:science_officer, "Data"]] |