Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I have an array of Active Record result and I want to iterate over each record to get a specific attribute and add all of them in one line with a nil check. Here is what I got so far

def total_cost(cost_rec)
    total= 0.0
    unless cost_rec.nil?
      cost_rec.each { |c| total += c.cost }
    end
    total
  end

Is there an elegant way to do the same thing in one line?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
4.1k views
Welcome To Ask or Share your Answers For Others

1 Answer

You could combine safe-navigation (to "hide" the nil check), summation inside the database (to avoid pulling a bunch of data out of the database that you don't need), and a #to_f call to hide the final nil check:

cost_rec&.sum(:cost).to_f

If the cost is an integer, then:

cost_rec&.sum(:cost).to_i

and if cost is a numeric inside the database and you don't want to worry about precision issues:

cost_rec&.sum(:cost).to_d

If cost_rec is an array rather than a relation (i.e. you've already pulled all the data out of the database), then one of:

cost_rec&.sum(&:cost).to_f
cost_rec&.sum(&:cost).to_i
cost_rec&.sum(&:cost).to_d

depending on what type cost is.

You could also use Kernel#Array to ignore nils (since Array(nil) is []) and ignore the difference between arrays and ActiveRecord relations (since #Array calls #to_ary and relations respond to that) and say:

Array(cost_rec).sum(&:cost)

that'll even allow cost_rec to be a single model instance. This also bypasses the need for the final #to_X call since [].sum is 0. The downside of this approach is that you can't push the summation into the database when cost_rec is a relation.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share

548k questions

547k answers

4 comments

86.3k users

...