Ruby的平均值和总和(n)

时间:2014-05-06 20:59:28

标签: ruby arrays sum rails-activerecord average

> Player.joins(:game).order('games.scheduled_start ASC').last(5).sum(:ppg)

=> NoMethodError: undefined method `+' for #<GamePlayer:0x007ff543cd05d8> 


> Player.joins(:game).order('games.scheduled_start ASC').sum(:ppg)

=> #<BigDecimal:7ff543cebc20,'0.30115E3',18(18)>

所以,我不明白为什么.last(n)打破了我在此系列上调用.average.sum的能力。

修改

[19] pry(main)> GamePlayer.order('id desc').limit(10).map{|x| x.ppg.to_f}
  GamePlayer Load (0.6ms)  SELECT "game_players".* FROM "game_players" ORDER BY id desc LIMIT 10
=> [14.0, 0.75, 1.2, 0.0, 2.55, 1.19, 2.04, 2.0, 0.0, 24.68]

[20] pry(main)> GamePlayer.order('id desc').limit(10).average(:ppg).to_f
  (74.4ms)  SELECT AVG("game_players"."ppg") AS avg_id FROM "game_players" LIMIT 10
=> 8.943831900603671

[21] pry(main)> GamePlayer.order('id desc').limit(50).average(:ppg).to_f
  (73.4ms)  SELECT AVG("game_players"."ppg") AS avg_id FROM "game_players" LIMIT 50
=> 8.943831900603671

[22] pry(main)> GamePlayer.order('id desc').limit(50).map{|x| x.ppg.to_f}.sum/50
  GamePlayer Load (0.9ms)  SELECT "game_players".* FROM "game_players" ORDER BY id desc LIMIT 50
=> 3.649800000000001

任何人都知道这种差异是什么?

1 个答案:

答案 0 :(得分:4)

last(5)(或更一般地last(n))是Array上定义的方法,这意味着您通过调用{{1}来构建ActiveRecord::Relation }将被计算到一个数组,然后将在该结果数组上调用Player.joins(:game).order('games.scheduled_start ASC')

Rails增加了在数组上调用last(5)的功能,但它的工作方式与sum上的工作方式不同(通过在每个对象上调用ActiveRecord::Relation和当前总和,以{开头{1}})。

相反,你可能想要使用它:

+

请注意,我已从0切换到players = Player.joins(:game).order('games.scheduled_start DESC').limit(5) sum = Player.joins(:game).where(id: players).sum(:ppg) ,因为限制始终会从一开始就采用元素。现在ASC实际上将被转换为相应的SQL聚合函数,该函数将在DESC - 列上运行。 需要sum - 子句才能触发子查询,以确保:ppg 仅适用于where选择的玩家。

如果您确实想使用数组(速度较慢),可以使用此方法:

sum

limit仅适用于players = Player.joins(:game).order('games.scheduled_start ASC').last(5) # builds the sum of all ppg-values of all players selected sum = players.sum(&:ppg) ,因为它未定义 average(甚至不在Rails中)。当然,你可以自己构建它,但同样,你可以自己构建它 ActiveRecord::Relation方法会更快。