在ruby哈希数组中重复数据删除并合并哈希属性

时间:2016-08-23 19:13:05

标签: ruby-on-rails arrays ruby hash

假设我有以下哈希数组:

[
{:first_name => "john", :last_name => "doe", :items_purchased => 1, :price => 5}, 
{:first_name => "john", :last_name => "doe", :items_purchased => 4, :price => 20}, 
{:first_name => "john", :last_name => "doe", :items_purchased => 4, :price => 20}, 
{:first_name => "jane", :last_name => "doe", :items_purchased => 2, :price => 7},
{:first_name => "jane", :last_name => "doe", :items_purchased => 3, :price => 14},
{:first_name => "test", :last_name => "user", :items_purchased => 1, :price => 4}
]

我想根据某些属性进行重复数据删除(本例中为first_namelast_name),然后将items_purchasedprice一起添加以接收以下输出

[
{:first_name => "john", :last_name => "doe", :items_purchased => 9, :price => 45}, 
{:first_name => "jane", :last_name => "doe", :items_purchased =>5, :price => 21},
{:first_name => "test", :last_name => "user", :items_purchased => 1, :price => 4}
]

有没有一种简单的方法可以在rails中完成此操作?我一直在用group_bymerge方法纠结我的想法,需要一些帮助。

由于

3 个答案:

答案 0 :(得分:1)

还有一种皮肤猫的方法:

 x = [
    {:first_name => "john", :last_name => "doe", :items_purchased => 1, :price => 5}, 
    {:first_name => "john", :last_name => "doe", :items_purchased => 4, :price => 20}, 
    {:first_name => "john", :last_name => "doe", :items_purchased => 4, :price => 20}, 
    {:first_name => "jane", :last_name => "doe", :items_purchased => 2, :price => 7},
    {:first_name => "jane", :last_name => "doe", :items_purchased => 3, :price => 14},
    {:first_name => "test", :last_name => "user", :items_purchased => 1, :price => 4}
]

group_keys = [:first_name,:last_name]

x.group_by{|h| h.values_at(*group_keys)}.map do |_,a|
     a.reduce do |memo,obj|
        memo.merge(obj){|k,v1,v2| group_keys.include?(k) ? v1 : v1 + v2}
    end
end

首先我们group_by使用相应的键,然后使用Enumerable#reduce

添加其他项目

既然您说过rails,如果您可以解释这些数据的来源,那么可能有一种更简单的数据库方式来处理这个问题。

答案 1 :(得分:0)

这似乎是一个复杂的解决方案。也许其他人可以提出更简单的事情:

IntegerField

如果您不在乎结果与我的结果完全相同:

x = [
{:first_name => "john", :last_name => "doe", :items_purchased => 1, :price => 5}, 
{:first_name => "john", :last_name => "doe", :items_purchased => 4, :price => 20}, 
{:first_name => "john", :last_name => "doe", :items_purchased => 4, :price => 20}, 
{:first_name => "jane", :last_name => "doe", :items_purchased => 2, :price => 7},
{:first_name => "jane", :last_name => "doe", :items_purchased => 3, :price => 14},
{:first_name => "test", :last_name => "user", :items_purchased => 1, :price => 4}
]

# Set the keys to group on:
group_keys = [:first_name,:last_name]

# For each group:
result =  x.group_by{|x| x.values_at(*group_keys)}.map do |k,v|
  # Create a hash:
  result_hash = Hash.new
  # For the group keys just add the vaules of the group by
  group_keys.zip(k).each{|x,y| result_hash[x] = y }

  # For the rest of the keys just add up the vaulus using inject:
  (v.first.keys-group_keys).each{|key| result_hash[key] = v.map{|x| x[key]}.inject(:+) }

  #return result_hash
  result_hash

end

p result #=> [{:first_name=>"john", :last_name=>"doe", :items_purchased=>9, :price=>45}, {:first_name=>"jane", :last_name=>"doe", :items_purchased=>5, :price=>21}, {:first_name=>"test", :last_name=>"user", :items_purchased=>1, :price=>4}]

答案 2 :(得分:0)

您可以将group_by与一个块一起使用全名分组:

grouped_data = data.group_by { |u| "#{u[:first_name]} #{u[:last_name]}" }

然后你可以遍历每个值,用reduce来总结你想要的任何东西:

grouped_data.map do |full_name, entries|
  entries.reduce(Hash.new(0)) do |output, entry|
    output[:items_purchased] += entry[:items_purchased]
    output[:price] += entry[:price]
    output
  end.merge(entries.first.slice(:first_name, :last_name))
end

将输出您想要的数据:

[
  {:items_purchased=>9, :price=>45, :first_name=>"john", :last_name=>"doe"},
  {:items_purchased=>5, :price=>21, :first_name=>"jane", :last_name=>"doe"},
  {:items_purchased=>1, :price=>4, :first_name=>"test", :last_name=>"user"}
]