Ruby哈希数组,比较两个键并求和另一个键/值

Ruby哈希数组,比较两个键并求和另一个键/值,ruby,arrays,hash,Ruby,Arrays,Hash,在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'} ] 我需要能够

在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.

这应该让你开始

items.group_by { |item| item.values_at(:unit, :type) }
输出

{
[“盎司”,“质量”]=>[
{:数量=>1,:单位=>“oz”,:类型=>“质量”},
{:数量=>4,:单位=>“盎司”,“类型=>“质量”}
],
[“盎司”,“体积”]=>[
{:数量=>5,:单位=>oz,:类型=>vol}
],
[“磅”,“质量”]=>[
{:数量=>1,:单位=>“磅”,“类型=>“质量”}
]
}
首先使用所需的键,然后将每个值中的
数量
放入一个散列,或者如果它们都是
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
是第二个示例输入数据

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

考虑中的安德鲁·马歇尔

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

你打算如何给加分?你的第二个例子没有意义,为什么结果中没有带单位
'o'
的散列?你是对的,只是编辑了它。你希望有很多这样的数据和工作要做吗?
减少(:+)
=>
求和(0)
(如果你使用的是activesupport)@Marianteisen Ruby没有
sum
方法。@Marianteisen Ruby没有
sum
方法,它只存在于ActiveSupport中。@AndrewMarshall但您错过了一个条目。。。那个奖金很重要……:):)@事实并非如此,OP的示例输出不符合其应如何生成的标准。见我对这个问题的评论。我的答案适用于类型和单位之间的任何“和”条件。是的,它是。。如果数组有多个散列,其中:qty为nil且单位为空(“”),那么它将只返回其中一个。不,我的意思是,您在答案末尾得到的结果不是代码实际返回的结果。这不是OP想要的格式。我知道我做了什么。我正在查看
result
的值。此外,你没有遵循OP的标准。如果
:unit
不为空,则删除该元素。