Ruby - 如何通过“.each”数组加速循环?

时间:2014-11-20 19:41:56

标签: ruby-on-rails ruby arrays performance each

我正在尝试提高代码性能的方法中使用这些模型和以下行。

class Location < ActiveRecord::Base
  belongs_to :company
end
class Company < ActiveRecord::Base
  has_many :locations
end

在方法中:

locations_company = []

###
found_locations = Location.within(distance, origin: from_result.split(',')).order("distance ASC")
### 0.002659s

###
found_locations.each do |location|
  locations_company << location.company
end
### 45.972285s

###
companies = locations_company.uniq{|x| x.id}
### 0.033029s

代码具有此功能 - 首先,抓取指定半径内的所有位置。然后,从每个找到的行中取出公司并将其保存到准备好的阵列中。这是有问题的部分 - 每个循环需要45秒才能处理。

然后从这个新创建的数组中删除重复项。

我仍然想知道是否有更好的方法来解决这种情况,但我恐怕现在还没有看到它,所以我想问你们怎样才能加速.each循环并将数据保存到数组中 - 在ruby中有更好的方法从对象中获取某些信息吗?

非常感谢您的时间,我整天沉浸在这个问题中,但仍然没有更有效的解决方案。

3 个答案:

答案 0 :(得分:6)

最好的方法是不循环。您的最终目标似乎是找到指定区域内的所有公司。

found_locations = Location.within(distance, origin: from_result.split(',')).order("distance ASC")
companies = Company.where(id: found_locations.pluck(:company_id).uniq)

答案 1 :(得分:1)

我相信一直需要的东西不是each,而是对数据库的查询。

第一行虽然构建查询但并没有真正运行它。

我相信如果您按如下方式编写代码:

locations_company = []

found_locations = Location.within(distance, origin: from_result.split(',')).order("distance ASC")

### this line will take most of the time
found_locations = found_locations.to_a
###    

###
found_locations.each do |location|
  locations_company << location.company_id
end
### 

###
companies = locations_company.uniq{|x| x.id}
###

您会发现each将花费更少的时间。您应该考虑优化查询。


正如@AlexPeachey在下面评论过的那样,location.company也会涉及对列表中每个位置的查询,因为它是一种关系。您可能希望通过添加以下内容来急切地加载公司:

found_locations = Location.includes(:company).within(distance, origin: from_result.split(',')).order("distance ASC")

答案 2 :(得分:1)

问题不在于每个问题,而在于查询仅在您开始迭代时才开始执行。 found_locations不是查询的结果,它是一个查询构建器,它将在需要时执行查询(例如,当您开始迭代结果时)。