Counting array elements in Ruby (unexpected results by the count( ) function)

时间:2016-04-21 21:52:13

标签: arrays ruby count findall

In my understanding the following ruby expressions should produce the same result.
Apparently I am missing something, this is a way too serious bug to go unnoticed...

# returns the number of ALL elements in the array
count = @quotation.quotation_items.count { |x| x.placement == current_placement}

# Does what I expect
count = (@quotation.quotation_items.find_all { |x| x.placement == current_placement }).length

quotation_items above is an ActiveRecord has_many association

3 个答案:

答案 0 :(得分:2)

#count does not take a block like that.

If you want to use conditions on a count, you would do:

@quotation.quotation_items.count(:conditions => "placement = #{current_placement}")

http://apidock.com/rails/ActiveRecord/Calculations/ClassMethods/count

答案 1 :(得分:1)

If you're using ActiveRecord you need to keep in mind that there's a point where it's compiling conditions and clauses for a query and a point where you have a result set. Certain things only work in one mode or the other, though it tries to keep things pretty consistent regardless.

In your case you are expecting count to work like Enumerable, but that's still a database-level operator.

To fix that:

@quotation.quotation_items.where(placement: current_placement).count

That composes a query that counts only the things you need, something approximating:

SELECT COUNT(*) FROM quotation_items WHERE quotation_id=? AND placement=?

That's something that yields a single number and is considerably different than selecting every record, instantiating into models, then counting those using Enumerable.

答案 2 :(得分:0)

Your usage of #count is incorrect.

I believe it doesn't accept a block. I'm not sure why it didn't return an error though.

you can use it like this :

count = @quotation.quotation_items.map{ |x| x.placement == current_placement}.count(true)