Help using ruby enumerator idioms


#1

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


#2

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


#3

Mischa F. 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.)