从动态密钥的复杂哈希数组中获取总和(以Rails方式)

时间:2015-10-02 08:21:23

标签: arrays ruby hash collections

我有一个哈希数组形式的复杂数据集合。我四处搜索,发现array.map{}array.collect可与.reduce().inject()方法一起使用,以获得收集总和。但是我只能通过一些非常简单的集合来实现这一点。在我的情况下,我无法获得一些数据。这是一些示例数据块。

    => [{"teacher_name"=>"Imran Ahmad", "categories"=>[{"category_name"=>"Presentation", "weight"=>24}, {"category_name"=>"Speaking", "weight"=>20}, {"category_name"=>"Communication", "weight"=>20}]},
 {"teacher_name"=>"t@kpi.com", "categories"=>[{"category_name"=>"Presentation", "weight"=>12}, {"category_name"=>"Speaking", "weight"=>5}, {"category_name"=>"Communication", "weight"=>5}]},
 {"teacher_name"=>"t2@kpi.com", "categories"=>[{"category_name"=>"Presentation", "weight"=>0}, {"category_name"=>"Speaking", "weight"=>0}, {"category_name"=>"Communication", "weight"=>0}]},
 {"teacher_name"=>"tt@kpi.com", "categories"=>[{"category_name"=>"Presentation", "weight"=>0}, {"category_name"=>"Speaking", "weight"=>0}, {"category_name"=>"Communication", "weight"=>0}]},
 {"teacher_name"=>"asd@kpi.con", "categories"=>[{"category_name"=>"Presentation", "weight"=>0}, {"category_name"=>"Speaking", "weight"=>0}, {"category_name"=>"Communication", "weight"=>0}]},
 {"teacher_name"=>"Tofiq Ahmad", "categories"=>[{"category_name"=>"Presentation", "weight"=>0}, {"category_name"=>"Speaking", "weight"=>0}, {"category_name"=>"Communication", "weight"=>0}]}]

我希望以下列形式总结一下;

"categories"=>[{"category_name"=>"Presentation", "weight"=>224}, {"category_name"=>"Speaking", "weight"=>220}, {"category_name"=>"Communication", "weight"=>320}]

这里每个哈希都是唯一的类别名称。假设类别Presentation的哈希表示每个哈希中此类别的所有weights的总和,依此类推。 使用这些方法使用short(“Rails方式”)对此进行排序的任何帮助都将非常感激。

注意:每次都不假设类别名称相同。不期望使用for循环的答案。

3 个答案:

答案 0 :(得分:0)

你可以这样试试:

# convert to list of categories hashes
list = array.map {|h| h['categories'] }.flatten

sum_hash = list.inject({}) do |carry, h|
  name = h['category_name']
  # initiate new Category or get if it's already existed
  carry[name] ||= {'category_name' => name, 'weight' => 0}
  # increase weight
  carry[name]['weight'] += h['weight']
  carry
end

你的输出:

{
  "Presentation"  => {"category_name"=>"Presentation", "weight"=>36},
  "Speaking"      => {"category_name"=>"Speaking", "weight"=>25},
  "Communication" => {"category_name"=>"Communication", "weight"=>25}
}

现在只需将收到的哈希转换为数组:

{ 'categories' => sum_hash.map { |_, v| v } }

答案 1 :(得分:0)

解决方案:

r = a.inject(Hash.new(0)) do |hash, e|
  e['categories'].each do |c|
    hash[c['category_name']] += c['weight']
  end
  hash
end

{'categories' => r.map { |k, v| {'category_name' => k, 'weight' => v} }}

结果:

{"categories"=>[
  {"category_name"=>"Presentation", "weight"=>36},
  {"category_name"=>"Speaking", "weight"=>25},
  {"category_name"=>"Communication", "weight"=>25}
]}

答案 2 :(得分:0)

在这里找到我的答案

sum_array = []
teachers_array = [{"teacher_name"=>"Imran Ahmad", "categories"=>[{"category_name"=>"Presentation", "weight"=>24}, {"category_name"=>"Speaking", "weight"=>20}, {"category_name"=>"Communication", "weight"=>20}]},
 {"teacher_name"=>"t@kpi.com", "categories"=>[{"category_name"=>"Presentation", "weight"=>12}, {"category_name"=>"Speaking", "weight"=>5}, {"category_name"=>"Communication", "weight"=>5}]},
 {"teacher_name"=>"t2@kpi.com", "categories"=>[{"category_name"=>"Presentation", "weight"=>0}, {"category_name"=>"Speaking", "weight"=>0}, {"category_name"=>"Communication", "weight"=>0}]},
 {"teacher_name"=>"tt@kpi.com", "categories"=>[{"category_name"=>"Presentation", "weight"=>0}, {"category_name"=>"Speaking", "weight"=>0}, {"category_name"=>"Communication", "weight"=>0}]},
 {"teacher_name"=>"asd@kpi.con", "categories"=>[{"category_name"=>"Presentation", "weight"=>0}, {"category_name"=>"Speaking", "weight"=>0}, {"category_name"=>"Communication", "weight"=>0}]},
 {"teacher_name"=>"Tofiq Ahmad", "categories"=>[{"category_name"=>"Presentation", "weight"=>0}, {"category_name"=>"Speaking", "weight"=>0}, {"category_name"=>"Communication", "weight"=>0}]}]

teachers_array.each do |teacher|

  teacher['categories'].each do |category|
    found = sum_array.select{|value| value['category_name'] == category['category_name']}[0]
    if found.present? then
      sum_array.collect! {|value|
        if value['category_name'] == category['category_name'] then
          value['weight'] += category['weight']
        end
        value
      }
    else
      sum_array << {'category_name' => category['category_name'], 'weight' => category['weight']}
    end
  end

end

<强>输出

[{"category_name"=>"Presentation", "weight"=>36}, {"category_name"=>"Speaking", "weight"=>25}, {"category_name"=>"Communication", "weight"=>25}]