Ruby's Partition Method
Tags: ruby
Published: 2020-12-13 23:00:40

Ruby's enumerable module is full of really delightful methods that can aid you in accomplishing a vast amount of tasks on collections. The focus of this post will be the partition instance method.

As a short detour before exploring the partition method, it's worth noting that in order to include the enumerable mixin within a class, whether it be a standard built in Ruby class or a class of your own, the class must first have an each method defined within the class. Only then can you include the enumerable mixin and gain access to all of the powerful methods that the module defines.

With that little factoid out of the way we can now look at the [partition](https://ruby-doc.org/core-2.5.1/Enumerable.html#method-i-partition) method.

From the official documentation, the partition method:
> Returns two arrays, the first containing the elements of enum for which the block evaluates to true, the second containing the rest.

Time for a simple example.

```ruby
2.6.3 :008 > nums = (1..25).to_a
 => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25] 

2.6.3 :009 > odd, even = nums.partition { |n| n.odd? }
 => [[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25], [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24]] 

# As provided by Emily Giurleo (see comment below), we can alternatively write the code above as follows:

odd, even = nums.partition(&:odd?)

# Pretty nice!!!

2.6.3 :010 > odd
 => [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25] 

2.6.3 :011 > even
 => [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24]
```

Pretty straight forward. On the first line we use Ruby's Range class to make a set of values that span from 1 to 25. We then call the to_a method on the range which places the range of values into an array. Next we declare two variables separated by a comma, each of which will receive one of the arrays which will be returned from the partition method. The first variable that is declared, in this case the odd variable, will reference the array that contains the values that evaluate to true based upon the logic within the block that is passed to the partition method. The second variable, even in this case, will reference the array of values which evaluate to false based upon the block passed to partition. We now have two completely new arrays containing the desired values based upon the logic in the block passed to partition. Important to note that the original nums array remains unchanged, the array is not mutated by sending the partition message to the nums variable.

Let's step things up some to perhaps a more practical example. Let's look at a use case that easily allows us to see what students passed and failed a certain subject. In this example we want to know which students passed and failed history. Using partition we can easily achieve this goal.

```ruby
2.6.3 :006 > collin = {name: "Collin", grades: {history: "B", math: "A", science: "B"}}
 => {:name=>"Collin", :grades=>{:history=>"B", :math=>"A", :science=>"B"}}

2.6.3 :007 > uma = {name: "Uma", grades: {history: "A", math: "B", science: "A"}}
 => {:name=>"Uma", :grades=>{:history=>"A", :math=>"B", :science=>"A"}}
 
2.6.3 :008 > jordan = {name: "Jordan", grades: {history: "C", math: "B", science: "B"}}
 => {:name=>"Jordan", :grades=>{:history=>"C", :math=>"B", :science=>"B"}}
 
2.6.3 :009 > henry = {name: "Henry", grades: {history: "F", math: "B", science: "B"}}
 => {:name=>"Henry", :grades=>{:history=>"F", :math=>"B", :science=>"B"}}

2.6.3 :010 > students = [collin, uma, jordan, henry]
 => [{:name=>"Collin", :grades=>{:history=>"B", :math=>"A", :science=>"B"}}, {:name=>"Uma", :grades=>{:history=>"A", :math=>"B", :science=>"A"}}, {:name=>"Jordan", :grades=>{:history=>"C", :math=>"B", :science=>"B"}}, {:name=>"Henry", :grades=>{:history=>"F", :math=>"B", :science=>"B"}}]

2.6.3 :011 > passed_history, failed_history = students.partition { |student| student[:grades][:history] <= "D" }
 => [[{:name=>"Collin", :grades=>{:history=>"B", :math=>"A", :science=>"B"}}, {:name=>"Uma", :grades=>{:history=>"A", :math=>"B", :science=>"A"}}, {:name=>"Jordan", :grades=>{:history=>"C", :math=>"B", :science=>"B"}}], [{:name=>"Henry", :grades=>{:history=>"F", :math=>"B", :science=>"B"}}]]

2.6.3 :012 > passed_history
 => [{:name=>"Collin", :grades=>{:history=>"B", :math=>"A", :science=>"B"}}, {:name=>"Uma", :grades=>{:history=>"A", :math=>"B", :science=>"A"}}, {:name=>"Jordan", :grades=>{:history=>"C", :math=>"B", :science=>"B"}}] 

2.6.3 :013 > failed_history
 => [{:name=>"Henry", :grades=>{:history=>"F", :math=>"B", :science=>"B"}}] 
``` 

I hope this gives you some ideas on how you can leverage the power Ruby's partition method to your advantage.

Happy Rubying!