【问题标题】:Ruby sum of elements from similar hashes [closed]来自类似哈希的元素的 Ruby 总和 [关闭]
【发布时间】:2020-05-25 05:15:42
【问题描述】:

假设我有这些记录,其中r_years 可以有任意数量的年份键:

Item.select('id','name','r_years').where(name:"N1")
...
"id" => 1, "name" => "N1", "r_years" => {"year2020" => "1","year2021" => "2", ...}
"id" => 2, "name" => "N1", "r_years" => {"year2020" => "2","year2021" => "3", ...}
...

我怎样才能得到 r_years 值的总和,对于每年的键,像这样:

@r_years_sum = {"year2020" => "3","year2021" => "5", ...}

【问题讨论】:

  • 这是查询的结果,还是您正在做一些转换? r_years 是否存储哈希值?
  • 是的,这是 activerecord 查询的结果(看起来像 AwesomePrint)。 r_years 存储带有年份值的哈希(它是一个序列化的哈希列)
  • 旁注:从数据库返回的数字数据确实是 strings 非常清楚地表明设计不佳。

标签: ruby-on-rails ruby activerecord hash


【解决方案1】:

您可以映射您的结果以仅获取 r_years 值,然后使用 reduce 并合并每年的每个值并将它们的值求和为整数:

items.map do |item|
  item['r_years']
end.reduce do |acc, item|
  item.merge(acc) { |_, oldval, newval| (oldval.to_i + newval.to_i).to_s }
end
# {"year2020"=>"3", "year2021"=>"5"}

【讨论】:

  • 您可以通过跳过映射来减少内存需求:items.reduce do |acc, item| acc.merge(item['r_years']) { |_, oldval, newval| (oldval.to_i + newval.to_i).to_s }。结束
【解决方案2】:
arr = [
  { "id"=>"1", "r_years"=>{ "2020"=>"1", "2021"=> "2", "2022"=>"3" } },
  { "id"=>"2", "r_years"=>{ "2020"=>"4", "2021"=> "5", "2022"=>"6" } },
  { "id"=>"3", "r_years"=>{ "2020"=>"7", "2021"=> "8", "2022"=>"9" } }
]

arr.each_with_object(Hash.new(0)) do |g,h|
  g["r_years"].each { |k,v| h[k] += v.to_i }
end.transform_values(&:to_s)
  #=> {"2020"=>"12", "2021"=>"15", "2022"=>"18"}

第一步是:

arr.each_with_object(Hash.new(0)) do |g,h|
  g["r_years"].each { |k,v| h[k] += v.to_i }
end
  #=> {"2020"=>12, "2021"=>15, "2022"=>18}

Hash#transform_values 然后用于将值转换为字符串。

这使用Hash::new 的第二种形式,它接受一个称为默认值 的参数。 h[c] += 1 扩展为 h[c] = h[c] + 1。如果h 没有键c,则等式右侧的h[c] 返回默认值零,产生h[c] = 0 + 1。

【讨论】:

  • 效果很好。谢谢!
【解决方案3】:

你可以试试这个……

arr = [
  { "id"=>"1", "r_years"=>{ "2020"=>"1", "2021"=> "2", "2022"=>"3" } },
  { "id"=>"2", "r_years"=>{ "2020"=>"4", "2021"=> "5", "2022"=>"6" } },
  { "id"=>"3", "r_years"=>{ "2020"=>"7", "2021"=> "8", "2022"=>"9" } }
]

res_hash=Hash.new(0)
arr.each do |x|
    x["r_years"].select{ |key,value| res_hash[key]+=value.to_i }
end


【讨论】:

    猜你喜欢
    • 2011-10-08
    • 2021-12-11
    • 2013-03-05
    • 2014-04-12
    • 2013-01-19
    • 1970-01-01
    • 2013-09-30
    • 1970-01-01
    • 2016-12-31
    相关资源
    最近更新 更多