2

在 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'}
]

如果数组有多个散列,其中:qtyisnil: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。

4

3 回答 3

8

首先使用group_by您想要的键,然后将每个值reduce中的qtys 放入单个哈希中,或者使用nilif they are all 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您的第二个样本输入数据在哪里。

于 2013-08-24T18:09:23.113 回答
3

你会想要enumberable.group_by

这应该让你开始

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"}
  ]
}
于 2013-08-24T18:06:28.623 回答
-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}]
于 2013-08-24T18:10:39.693 回答