[英]What is the best way to get unique elements of an array of activerecord objects based on attributes of the object?
In my application I am trying to display only unique elements of an array of activerecord objects(loss_reports) based on two attributes of a loss_report. 在我的应用程序中,我试图基于loss_report的两个属性仅显示activerecord对象(loss_reports)数组的唯一元素。
Schema 架构图
class Agent < ActiveRecord::Base
has_many :loss_reports, :through => policy
end
class LossReport < ActiveRecord::Base
belongs_to :agent
end
I first tried to override the eql? 我首先尝试覆盖eql? and hash method of a LossReport so that I could do something similar to:
和LossReport的哈希方法,以便我可以执行以下操作:
Option 1: 选项1:
class LossReport ...
def eql? other
self.policy_id == other.policy_id && loss_occurred_on.hash == self.loss_occurred_on
end
def hash
policy_id + loss_occurred_on.hash
end
end
class Agent ...
def unique_losses
loss_reports.to_set
end
end
but quickly removed the code because of ActiveRecord already overriding the methods and my not being sure of the repercussions. 但由于ActiveRecord已经覆盖了方法,并且我不确定其影响,因此很快删除了代码。
Option 2: 选项2:
class Agent ...
def unique_losses
loss_reports.sort{|l1,l2| l2.created_at <=> l1.created_at}.group_by{|l| (l.policy_id + l.loss_occurred_on.hash)}.collect{|hl| hl[-1].first}
end
end
Option 3: 选项3:
class Agent
def unique_losses
hsh_array = []
unique = []
loss_reports.sort{|l1,l2| l2.created_at <=> l1.created_at}.each do |l|
unique << l unless hsh_array.include?(l.hsh)
hsh_array << l.hsh
end
unique
end
end
Benchmark results: 基准结果:
Benchmark.bmbm do |bm|
bm.report("option 2") do
losses.sort{|l1,l2| l2.created_at <=> l1.created_at}.group_by{|l| (l.policy_id + l.loss_occurred_on.hash)}.collect{|hl| hl[-1].first}
end
bm.report("option 3") do
hsh_array,unique = [],[]
losses.sort{|l1,l2| l2.created_at <=> l1.created_at}.each do |l|
unique << l unless hsh_array.include?(l.policy_id+l.loss_occurred_on.hash)
hsh_array << l.policy_id + l.loss_occurred_on.hash
end
end
end
Rehearsal --------------------------------------------
option 2 0.400000 0.000000 0.400000 ( 0.407615)
option 3 0.250000 0.000000 0.250000 ( 0.254399)
----------------------------------- total: 0.650000sec
user system total real
option 2 0.400000 0.000000 0.400000 ( 0.403535)
option 3 0.250000 0.000000 0.250000 ( 0.262578)
Neither way feels right but both work. 两种方法都不对,但两种方法都可行。 Which is the best option or is there an even better way?
哪个是最佳选择,还是有更好的方法?
I have no idea about benchmarks, but it seems like inject
would be the simplest way: 我对基准测试一无所知,但
inject
似乎是最简单的方法:
loss_reports.inject([]) do |arr, report|
arr << report unless arr.detect{|r| ... }
end
Or maybe even better would be to define a named_scope with a custom SQL group by... 甚至更好的办法是通过以下方式定义一个具有自定义SQL组的named_scope:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.