Help using ruby enumerator idioms

Hi,

In Ruby, when I see something like:

h = []

x.each do

...

end

h

Usually means that I can refactor it to use map, inject, select, or
reject.

However, I am unsure how to do this for the code below:

         h = Hash.new {|hash, key| hash[key] = {}}

   some_hash_of_hashes.each do |hash_key, sub_hash|
     sub_hash.each {|key, value| h[key][hash_key] = value }
   end

   h

Let me know if anyone has any ideas.

M

···

--
Posted via http://www.ruby-forum.com/.

Mischa Fierer wrote:

Hi,

In Ruby, when I see something like:

h =

x.each do

...

end

h

Usually means that I can refactor it to use map, inject, select, or
reject.

Yes, I do the same. In a broader sense, functional style is often
shorter and less error-prone. Map, inject, select are just examples
of the functional idiom smuggled into ruby.

In this case, a hash-of-hash merge function is needed to reorder keys
in a clean way.

···

#
# hoh_merge(
# { :x => { :y => :foo } },
# { :x => { :z => :bar } }
# )
# #=> {:x=>{:y=>:foo, :z=>:bar}}
#
def hoh_merge(a, b)
  b.inject(a) { |acc, (key, inner_hash)|
    acc.merge(
      key => (
        if existing = a[key]
          existing.merge(inner_hash)
        else
          inner_hash
        end
      )
    )
  }
end

data = {
  :flintstone => {
    :husband => :fred,
    :wife => :wilma,
  },
  :rubble => {
    :husband => :barney,
    :wife => :betty,
  },
}

# original imperative version

h = Hash.new { |hash, key| hash[key] = Hash.new }
data.each { |hash_key, inner_hash|
  inner_hash.each { |key, value|
    h[key][hash_key] = value
  }
}

# pure functional version

h2 = data.inject(Hash.new) { |acc, (hash_key, inner_hash)|
  inner_hash.keys.inject(acc) { |inner_acc, key|
    hoh_merge(inner_acc, key => { hash_key => inner_hash[key] })
  }
}

require 'pp'

pp h
pp h2

#=>
# {:wife=>{:rubble=>:betty, :flintstone=>:wilma},
# :husband=>{:rubble=>:barney, :flintstone=>:fred}}
# {:wife=>{:rubble=>:betty, :flintstone=>:wilma},
# :husband=>{:rubble=>:barney, :flintstone=>:fred}}

I wrote a purely-functional hoh_merge just for fun. An imperative
method would be more efficient (modifying its first argument),

h2 = data.inject(Hash.new) { |acc, (hash_key, inner_hash)|
  inner_hash.keys.inject(acc) { |inner_acc, key|
    hoh_merge!(inner_acc, key => { hash_key => inner_hash[key] })
  }
}

But here inner_acc is always identical to acc, making the inject just
for show. You're back to using #each.

I guess the moral of the story is that functional style in ruby
realistically applies only to flat arrays and hashes. Once we reach
the hash-of-hashes realm, imperative constructs are more suitable.

Lazy evaluation is needed to be efficient, recursive, and purely
functional all at the same time. (See Haskell.)
--
Posted via http://www.ruby-forum.com/\.

But here inner_acc is always identical to acc, making the inject just
for show. You're back to using #each.

I guess the moral of the story is that functional style in ruby
realistically applies only to flat arrays and hashes. Once we reach
the hash-of-hashes realm, imperative constructs are more suitable.

Lazy evaluation is needed to be efficient, recursive, and purely
functional all at the same time. (See Haskell.)

Interesting, thanks a ton for the reply.

I think you may be right that for hashes of hashes imperative style Ruby
starts to make more sense.

This has been hitting me a lot lately, as one of the projects I'm
working on has a lot of hashes of hashes (data crunching). I used the
inject style a few times, but as you note, it becomes mostly just for
show.

M

···

--
Posted via http://www.ruby-forum.com/\.