require 'enumerator' module Enumerable # Like #map/#collect, but generates a Hash. The block # is expected to return two values: the key and the value for the new hash. # # numbers = (1..3) # squares = numbers.collate { |n| [n, n*n] } # { 1=>1, 2=>4, 3=>9 } # sq_roots = numbers.collate { |n| [n*n, n] } # { 1=>1, 4=>2, 9=>3 } # # CREDIT: Trans # CREDIT: Andrew Dudzik (adudzik) def collate(&yld) if yld inject({}) do |h, *kv| # Used to be inject({}) do |h,kv| r = *yld[*kv] # The *-op works differnt from to_a on single element hash!!! nk, nv = *r # Used to be nk, nv = *yld[*kv].to_a.flatten h[nk] = nv h end else Enumerator.new(self,:collate) # Used to be Hash[*self.to_a] or Hash[*self.to_a.flatten] end end alias :graph :collate # Returns a new hash built by iterating through each key,value # pair and updating the new hash. #def collate #:yield: # newhash = {} # each_pair{ |k,v| newhash.update(yield(k,v)) } # newhash #end end class Hash # In place version of #collate. # # NOTE Hash#collate! is only useful for Hash. It is not generally # applicable to Enumerable. def collate!(&yld) replace(collate(&yld)) end # Alias for #collate! (THIS WILL BE DEPRECATED) alias :graph! :collate! end # _____ _ # |_ _|__ ___| |_ # | |/ _ \/ __| __| # | | __/\__ \ |_ # |_|\___||___/\__| # =begin test require 'test/unit' class TestEnumerableCollate < Test::Unit::TestCase def test_collate_01 a = { :a => 1, :b => 2, :c => 3 } e = { :a => 2, :b => 3, :c => 4 } assert_equal( e, a.collate{ |k,v| { k => v+1 } } ) end def test_collate_02 numbers = (1..3) squares = numbers.collate{ |n| [n, n*n] } assert_equal( {1=>1, 2=>4, 3=>9}, squares ) end def test_collate_03 numbers = (1..3) sq_roots = numbers.collate{ |n| [n*n, n] } assert_equal( {1=>1, 4=>2, 9=>3}, sq_roots ) end def test_collate_01! a = { :a => 1, :b => 2, :c => 3 } e = { :a => 2, :b => 3, :c => 4 } a.collate!{ |k,v| { k => v+1 } } assert_equal( e, a ) end def test_collate_02! h = {:a=>1,:b=>2,:c=>3} h.collate!{ |k,v| [v, v*v] } assert_equal( {1=>1, 2=>4, 3=>9}, h ) end end =end