Ruby on rails 如何对具有相同结构的数组中的值进行分组和求和

Ruby on rails 如何对具有相同结构的数组中的值进行分组和求和,ruby-on-rails,ruby,Ruby On Rails,Ruby,我在每个活动的数据属性中都有这个数组,对应于按小时计算的课堂出勤率 我需要按小时计算每次活动的总出席人数。 是否可以对其进行分组和求和 例如: 小时7的正确结果为50+60=110 [{:name=>"cardio", :data=>[["06", 999], ["07", 50], ["08", 0], ["09", 154], ["10", 1059], ["11", 90], ["12", 30], ["13", 0], ["14", 0], ["15", 0], ["16"

我在每个活动的数据属性中都有这个数组,对应于按小时计算的课堂出勤率

我需要按小时计算每次活动的总出席人数。 是否可以对其进行分组和求和

例如: 小时7的正确结果为50+60=110

[{:name=>"cardio", 
:data=>[["06", 999], ["07", 50], ["08", 0], ["09", 154], ["10", 1059], ["11", 90], ["12", 30], ["13", 0], ["14", 0], ["15", 0], ["16", 0], ["17", 0], ["18", 0], ["19", 0], ["20", 0], ["21", 0], ["22", 0], ["23", 0]]}, 
:name=>"swimming", 
:data=>[["06", 0], ["07", 60], ["08", 0], ["09", 0], ["10", 90], ["11", 50], ["12", 0], ["13", 0], ["14", 0], ["15", 0], ["16", 0], ["17", 0], ["18", 0], ["19", 0], ["20", 0], ["21", 0], ["22", 0], ["23", 0]]}]
预期结果:

:data=>[["06", 999], ["07", 110], ["08", 0], ["09", 154], ["10", 1149], ["11", 140], ["12", 30], ["13", 0], ["14", 0], ["15", 0], ["16", 0], ["17", 0], ["18", 0], ["19", 0], ["20", 0], ["21", 0], ["22", 0], ["23", 0]
如何对具有相同结构的数组中的值进行分组和求和

你应该这样做:

[{:name=>"cardio", 
:data=>[["06", 999], ["07", 50], ["08", 0], ["09", 154], ["10", 1059], ["11", 90], ["12", 30], ["13", 0], ["14", 0], ["15", 0], ["16", 0], ["17", 0], ["18", 0], ["19", 0], ["20", 0], ["21", 0], ["22", 0], ["23", 0]]}, 
:name=>"swimming", 
:data=>[["06", 0], ["07", 60], ["08", 0], ["09", 0], ["10", 90], ["11", 50], ["12", 0], ["13", 0], ["14", 0], ["15", 0], ["16", 0], ["17", 0], ["18", 0], ["19", 0], ["20", 0], ["21", 0], ["22", 0], ["23", 0]]}]
试试这个:

act.map{|h| h[:data]}.flatten(1).group_by(&:first).map { |k,v| [k, v.map(&:last).inject(:+)] }
# => [["06", 999], ["07", 110], ["08", 0], ["09", 154], ["10", 1149], ["11", 140], ["12", 30], ["13", 0], ["14", 0], ["15", 0], ["16", 0], ["17", 0], ["18", 0], ["19", 0], ["20", 0], ["21", 0], ["22", 0], ["23", 0]] 
希望这对您有所帮助,因为:

act=[{:name=>"cardio", 
:data=>[["06", 999], ["07", 50], ["08", 0], ["09", 154], ["10", 1059], ["11", 90], ["12", 30], ["13", 0], ["14", 0], ["15", 0], ["16", 0], ["17", 0], ["18", 0], ["19", 0], ["20", 0], ["21", 0], ["22", 0], ["23", 0]]}, 
{:name=>"swimming", 
:data=>[["06", 0], ["07", 60], ["08", 0], ["09", 0], ["10", 90], ["11", 50], ["12", 0], ["13", 0], ["14", 0], ["15", 0], ["16", 0], ["17", 0], ["18", 0], ["19", 0], ["20", 0], ["21", 0], ["22", 0], ["23", 0]]}]
你可以做:

> act.map{ |h| h[:data] }
       .flatten(1)
       .group_by{ |h,n| h }
       .map { |k,v| [k, v.map(&:last).sum] }
=> [["06", 999], ["07", 110], ["08", 0], ["09", 154], ["10", 1149], ["11", 140], ["12", 30], ["13", 0], ["14", 0], ["15", 0], ["16", 0], ["17", 0], ["18", 0], ["19", 0], ["20", 0], ["21", 0], ["22", 0], ["23", 0]]
或者

也行

actions=[{:name=>"cardio", 
:data=>[["06", 999], ["07", 50], ["08", 0], ["09", 154], ["10", 1059], ["11", 90], ["12", 30], ["13", 0], ["14", 0], ["15", 0], ["16", 0], ["17", 0], ["18", 0], ["19", 0], ["20", 0], ["21", 0], ["22", 0], ["23", 0]]}, 
{:name=>"swimming", 
:data=>[["06", 0], ["07", 60], ["08", 0], ["09", 0], ["10", 90], ["11", 50], ["12", 0], ["13", 0], ["14", 0], ["15", 0], ["16", 0], ["17", 0], ["18", 0], ["19", 0], ["20", 0], ["21", 0], ["22", 0], ["23", 0]]}]

actions.map{|act| act[:data]}.reduce({}) do |acc, data|
  acc.merge(data.to_h) {|k, v1, v2| v1 + v2}
end.to_a
这个解决方案利用了Ruby的
散列
保持插入顺序这一事实


此算法的优点是允许在任一数据数组中丢失键。

情况1:data的值是大小相同的数组,其元素(两个元素数组)按其第一个元素的顺序排列相同。

arr = [{ :name=>"cardio",   :data=>[["06", 999], ["07", 50], ["08", 0]] }, 
       { :name=>"swimming", :data=>[["06",   0], ["07", 60], ["08", 0]] }]

a, b = arr.map { |h| h[:data].transpose }.transpose
  #=> [[["06", "07", "08"], ["06", "07", "08"]], [[999, 50, 0], [0, 60, 0]]]
{ :data=>a.first.zip(b.transpose.map { |col| col.reduce(:+) }) }
  #=> {:data=>[["06", 999], ["07", 110], ["08", 0]]}
情况2:
:data
的值是大小可能不同的数组,其元素(两个元素数组)的顺序可能与其第一个元素的顺序不同

arr = [{ :name=>"cardio",   :data=>[["05", 999], ["07", 50], ["08",  0]] }, 
       { :name=>"swimming", :data=>[["08", 300], ["04", 33], ["07", 60]] }] 

{ :data=>arr.flat_map { |g| g[:data] }.
    each_with_object(Hash.new(0)) { |(f,v),h| h[f] += v }.
    sort.
    to_a }
  #=>  {:data=>[["04", 33], ["05", 999], ["07", 110], ["08", 300]]}
注:

  • 根据要求,可能不需要排序
  • 无论是否并行定义
    :data
    的值,都可以使用第二种方法
  • 第二个方法使用的形式是一个参数(默认值),这里的参数为零。这有时被称为计数散列。详情见文件

有趣!我从来没有想过这样使用
Array#transpose
arr = [{ :name=>"cardio",   :data=>[["05", 999], ["07", 50], ["08",  0]] }, 
       { :name=>"swimming", :data=>[["08", 300], ["04", 33], ["07", 60]] }] 

{ :data=>arr.flat_map { |g| g[:data] }.
    each_with_object(Hash.new(0)) { |(f,v),h| h[f] += v }.
    sort.
    to_a }
  #=>  {:data=>[["04", 33], ["05", 999], ["07", 110], ["08", 300]]}