Daily Code Reading #5 – Facets Hash#group_by_value

To finish up this week of code reading, I read through Hash#group_by_value.

The Code

1
2
3
4
5
6
# File lib/core/facets/hash/group_by_value.rb, line 42
  def group_by_value
    res = {}
    each{|k, v| (res[v] ||= []) << k}
    res
  end

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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#!/usr/bin/ruby -wKU
#
# Code Reading #5
require '../base'
require "facets/hash/group_by_value"
 
class Example
  def self.create
    # Servers and their OS version string
    {
      :load_balancer => '10.10',
      :web_server_one => '10.10',
      :web_server_two => '10.10',
      :app_server_one => '10.04',
      :app_server_two => '10.04',
      :database_server_one => '9.10',
      :memcached_server_one => 'sid',
      :memcached_server_two => 'sid',
      :background_server => '10.10'
    }
  end
end
 
ap(Example.create.group_by_value)
 
class HashGroupByValue < Test::Unit::TestCase
  def test_should_group_servers_by_version
    result = Example.create.group_by_value
 
    assert result['9.10'].include? :database_server_one
 
    assert result['10.04'].include? :app_server_one
    assert result['10.04'].include? :app_server_two
 
    assert result['10.10'].include? :background_server
    assert result['10.10'].include? :load_balancer
    assert result['10.10'].include? :web_server_one
    assert result['10.10'].include? :web_server_two
 
    assert result['sid'].include? :memcached_server_one
    assert result['sid'].include? :memcached_server_one
  end
 
end

On github

Review

This is another good Hash method that will be useful when working with data. I’ve used Rails’ Hash#group_by a lot but I usually end up with a lot of extra data in the inner elements.

I also like how #group_by_value uses the single statement to initialize the result and add the key to it. (res[v] ||= []) will either:

  • initialize the new key and returns the empty array, or
  • return the existing element (an array)

This lets << k append onto the array directly. Compare that one line to the alternative and it’s easy to see how elegant the initializer can be.

1
2
res[v] ||= []
res[v] &lt;&lt; k