sum array of hashes based on other fields in hash
I have an array of hashes that looks like this:
[{:head_count=>150.5, :group=>"NW", :estimated_ship_date=>"201105", :yard=>"wcc"},
{:head_count=>201.0, :group=>"NW", :estimated_ship_date=>"201105", :yard=>"wcc"},
{:head_count=>103.5, :group=>"NW", :estimated_ship_date=>"201104", :yard=>"nyssa"}]
I am looking to create a hash from this data that looks like this:
{
"wcc" =>
{
"NW" =>
{
"201105" => 351.5 # This being a sum
}
}
"nyssa" =>
{
"NW" =>
{
"201104" => 103.5 # This being a sum
}
}
}
I am not sure what other data I c开发者_Python百科an provide.
I tried a collect, but couldn't figure out where to even start.
Thank you
A slightly different version using the default proc of Hashes to auto-vivify the containers:
a = [
{:head_count=>150.5, :group=>"NW", :estimated_ship_date=>"201105", :yard=>"wcc"},
{:head_count=>201.0, :group=>"NW", :estimated_ship_date=>"201105", :yard=>"wcc"},
{:head_count=>103.5, :group=>"NW", :estimated_ship_date=>"201104", :yard=>"nyssa"}
]
yards = Hash.new{ |h,yard|
h[yard]=Hash.new{ |h,group|
h[group]=Hash.new{ |h,est_date|
h[est_date]=0
}
}
}
a.each do |h|
yards[h[:yard]][h[:group]][h[:estimated_ship_date]] += h[:head_count]
end
p yards
#=> {"wcc"=>{"NW"=>{"201105"=>351.5}}, "nyssa"=>{"NW"=>{"201104"=>103.5}}}
I'd just use a simple loop.
a = [{:head_count=>150.5, :group=>"NW", :estimated_ship_date=>"201105", :yard=>"wcc"},
{:head_count=>201.0, :group=>"NW", :estimated_ship_date=>"201105", :yard=>"wcc"},
{:head_count=>103.5, :group=>"NW", :estimated_ship_date=>"201104", :yard=>"nyssa"}]
yards = {}
a.each do |h|
yard = yards[h[:yard]] ||= {}
group = yard[h[:group]] ||= {}
group[h[:estimated_ship_date]] ||= 0.0
group[h[:estimated_ship_date]] += h[:head_count]
end
# yards => {"wcc"=>{"NW"=>{"201105"=>351.5}}, "nyssa"=>{"NW"=>{"201104"=>103.5}}}
Here's my solution.
yards = []
a.select{|x| yards << x[:yard]}
sol = Hash.new{|k,v| k[v] = Hash.new{|k,v| k[v] = {} } }
yards.uniq.map do |x|
a.select{|y| x == y[:yard]}.flatten.map do |z|
sol[x][z[:group]][z[:estimated_ship_date]] = 0.0
sol[x][z[:group]][z[:estimated_ship_date]] += z[:head_count]
end
end
Your initial array is a. And the solutions is sol. I hope this looks readable
x = [
{:head_count=>100, :group=>"NE", :estimated_ship_date=>"201103", :yard=>"wcc"},
{:head_count=>200, :group=>"NW", :estimated_ship_date=>"201104", :yard=>"wcc"},
{:head_count=>300, :group=>"NW", :estimated_ship_date=>"201105", :yard=>"wcc"},
{:head_count=>400, :group=>"NW", :estimated_ship_date=>"201105", :yard=>"wcc"},
{:head_count=>500, :group=>"NW", :estimated_ship_date=>"201104", :yard=>"nyssa"}]
p Hash[ x.group_by{ |i| i[:yard] }.map { |i,j|
[i, Hash[ j.group_by { |i| i[:group] }.map { |i,j|
[i, Hash[ j.group_by { |i| i[:estimated_ship_date] }.map{ |i,j|
[i, j.map{ |i| i[:head_count] }.inject(:+)]
} ] ]
} ] ]
} ]
{
"wcc"=>
{
"NE"=>
{
"201103"=>100
},
"NW"=>
{
"201104"=>200,
"201105"=>700
}
},
"nyssa"=>
{
"NW"=>
{
"201104"=>500
}
}
}
精彩评论