array_1 = [{:address=>"123 Main St", :locality=>"New York",
:neighbourhood=>"Main", :lot_front=>18.0, :lot_depth=>37.0,
:property_type=>"Detached", :asking_price=>156000},
{:address=>"321 Niam St", :locality=>"New York",
:neighbourhood=>"Niam", :lot_front=>18.0, :lot_depth=>37.0,
:property_type=>"Unattached", :asking_price=>100000}]
array_2 = [{:address=>"121 Orchard Heights Dr", :locality=>"New York",
:neighbourhood=>"Main", :lot_front=>19.0, :lot_depth=>46.0,
:property_type=>"Detached", :closed_price=>270000,
:sold_date=>"2013-04-02"},
{:address=>"121 Orchard Heights Dr", :locality=>"New York",
:neighbourhood=>"Niam", :lot_front=>19.0, :lot_depth=>46.0,
:property_type=>"Detached", :closed_price=>600000,
:sold_date=>"2013-04-02"},
{:address=>"121 Orchard Heights Dr", :locality=>"New York",
:neighbourhood=>"Main", :lot_front=>19.0, :lot_depth=>46.0,
:property_type=>"Detached", :closed_price=>400000,
:sold_date=>"2013-04-02"}]
First construct a hash h2
whose keys are distinct pairs of the values of :locality
and neighborhourhood
in array_2
and whose values are the elements of h2
(hashes) whose values for those keys correspond to the elements of the key:
h2 = array_2.each_with_object(Hash.new { |h,k| h[k] = [] }) do |g,h|
h[[g[:locality], g[:neighbourhood]]] << g
end
#=> {["New York", "Main"]=>[
# {:address=>"121 Orchard Heights Dr", :locality=>"New York",
# :neighbourhood=>"Main", :lot_front=>19.0, :lot_depth=>46.0,
# :property_type=>"Detached", :closed_price=>270000,
# :sold_date=>"2013-04-02"},
# {:address=>"121 Orchard Heights Dr", :locality=>"New York",
# :neighbourhood=>"Main", :lot_front=>19.0, :lot_depth=>46.0,
# :property_type=>"Detached", :closed_price=>400000,
# :sold_date=>"2013-04-02"}
# ],
# ["New York", "Niam"]=>[
# {:address=>"121 Orchard Heights Dr", :locality=>"New York",
# :neighbourhood=>"Niam", :lot_front=>19.0, :lot_depth=>46.0,
# :property_type=>"Detached", :closed_price=>600000,
# :sold_date=>"2013-04-02"}
# ]
# }
See the form of Hash::new that takes a block.
Now merge each element (hash) of array_1
with a hash having the single key :closed_price
whose value is the average of the values of :close_price
taken over all elements in h2
for which the values of :locality
and neighborhourhood
are the same as those for the element of array_1
being matched:
array_1.map do |g|
a2s = h2[ [g[:locality], g[:neighbourhood]] ]
g.merge( closed_avg: a2s.sum { |g| g[:closed_price] }.fdiv(a2s.size) )
end
[{:address=>"123 Main St", :locality=>"New York",
:neighbourhood=>"Main", :lot_front=>18.0, :lot_depth=>37.0,
:property_type=>"Detached", :asking_price=>156000, :closed_avg=>335000.0},
{:address=>"321 Niam St", :locality=>"New York",
:neighbourhood=>"Niam", :lot_front=>18.0, :lot_depth=>37.0,
:property_type=>"Unattached", :asking_price=>100000, :closed_avg=>600000.0}]
See Hash#merge and Numeric#fdiv. merge
does not mutate (modify) any of the elements (hashes) of array_1
.
The construction of h2
is effectively the same as the following:
h2 = {}
array_2.each do |g|
arr = [g[:locality], g[:neighbourhood]]
h2[arr] = [] unless h2.key?(arr)
h2[arr] << g
end
h2