在Ruby中,我有以下哈希数组:
[
{:qty => 1, :unit => 'oz', :type => 'mass'},
{:qty => 5, :unit => 'oz', :type => 'vol'},
{:qty => 4, :unit => 'oz', :type => 'mass'},
{:qty => 1, :unit => 'lbs', :type => 'mass'}
]
我需要做的是按:unit
和:type
比较元素,然后在它们相同时对:qty
求和。生成的数组应如下所示:
[
{:qty => 5, :unit => 'oz', :type => 'mass'},
{:qty => 5, :unit => 'oz', :type => 'vol'},
{:qty => 1, :unit => 'lbs', :type => 'mass'}
]
如果数组有多个哈希值,:qty
为nil
且:unit
为空(""
),那么它只会返回其中一个哈希值。所以为了扩展上面的例子,这个:
[
{:qty => 1, :unit => 'oz', :type => 'mass'},
{:qty => nil, :unit => '', :type => 'Foo'},
{:qty => 5, :unit => 'oz', :type => 'vol'},
{:qty => 4, :unit => 'oz', :type => 'mass'},
{:qty => 1, :unit => 'lbs', :type => 'mass'},
{:qty => nil, :unit => '', :type => 'Foo'}
]
会变成这样:
[
{:qty => 5, :unit => 'oz', :type => 'mass'},
{:qty => nil, :unit => '', :type => 'Foo'},
{:qty => 5, :unit => 'oz', :type => 'vol'},
{:qty => 1, :unit => 'lbs', :type => 'mass'}
]
编辑:对不起,在第二个例子中犯了一个错误......它不应该有o。
答案 0 :(得分:8)
首先将group_by
与您想要的密钥一起使用,然后reduce
将每个值中的qty
分成一个哈希值,或者如果它们都是nil
则使用nil
properties.group_by do |property|
property.values_at :type, :unit
end.map do |(type, unit), properties|
quantities = properties.map { |p| p[:qty] }
qty = quantities.all? ? quantities.reduce(:+) : nil
{ type: type, unit: unit, qty: qty }
end
#=> [{:type=>"mass", :unit=>"oz", :qty=>5},
# {:type=>"Foo", :unit=>"", :qty=>nil},
# {:type=>"vol", :unit=>"oz", :qty=>5},
# {:type=>"mass", :unit=>"lbs", :qty=>1}]
:
properties
{{1}}是您的第二个样本输入数据。
答案 1 :(得分:3)
这应该让你入门
items.group_by { |item| item.values_at(:unit, :type) }
输出
{
["oz", "mass"]=> [
{:qty=>1, :unit=>"oz", :type=>"mass"},
{:qty=>4, :unit=>"oz", :type=>"mass"}
],
["oz", "vol"]=>[
{:qty=>5, :unit=>"oz", :type=>"vol"}
],
["lbs", "mass"]=>[
{:qty=>1, :unit=>"lbs", :type=>"mass"}
]
}
答案 2 :(得分:-1)
ar = [{:qty => 1, :unit => 'oz', :type => 'mass'}, {:qty => nil, :unit => '', :type => 'Foo'},
{:qty => 5, :unit => 'oz', :type => 'vol'},
{:qty => 4, :unit => 'oz', :type => 'mass'}, {:qty => 1, :unit => 'lbs', :type => 'mass'},
{:qty => nil, :unit => 'o', :type => 'Foo'}]
result = ar.each_with_object(Hash.new(0)) do |e,hsh|
if hsh.has_key?({:unit => e[:unit], :type => e[:type]})
hsh[{:unit => e[:unit], :type => e[:type]}] += e[:qty]
else
hsh[{:unit => e[:unit], :type => e[:type]}] = e[:qty]
end
end
result.map{|k,v| k[:qty] = v;k }.delete_if{|h| h[:qty].nil? and !h[:unit].empty? }
# => [{:unit=>"oz", :type=>"mass", :qty=>5},
# {:unit=>"", :type=>"Foo", :qty=>nil},
# {:unit=>"oz", :type=>"vol", :qty=>5},
# {:unit=>"lbs", :type=>"mass", :qty=>1}]
考虑 @Andrew Marshall
ar = [{:qty => 1, :unit => 'oz', :type => 'mass'}, {:qty => nil, :unit => '', :type => 'Foo'},
{:qty => 5, :unit => 'oz', :type => 'vol'},
{:qty => 4, :unit => 'oz', :type => 'mass'}, {:qty => 1, :unit => 'lbs', :type => 'mass'},
{:qty => nil, :unit => 'o', :type => 'Foo'}]
result = ar.each_with_object(Hash.new(0)) do |e,hsh|
if hsh.has_key?({:unit => e[:unit], :type => e[:type]})
hsh[{:unit => e[:unit], :type => e[:type]}] += e[:qty]
else
hsh[{:unit => e[:unit], :type => e[:type]}] = e[:qty]
end
end
result.map{|k,v| k[:qty] = v;k }.delete_if{|h| h[:qty].nil? and h[:unit].empty? }
# => [{:unit=>"oz", :type=>"mass", :qty=>5},
# {:unit=>"oz", :type=>"vol", :qty=>5},
# {:unit=>"lbs", :type=>"mass", :qty=>1},
# {:unit=>"o", :type=>"Foo", :qty=>nil}]