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 |
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] << k |