Dans mon application, j'essaie de n'afficher que des éléments uniques d'un tableau d'objets d'enregistrement actif (loss_reports) basés sur deux attributs d'un rapport de perte.Quelle est la meilleure façon d'obtenir des éléments uniques d'un tableau d'objets activerecord en fonction des attributs de l'objet?
Schéma
class Agent < ActiveRecord::Base
has_many :loss_reports, :through => policy
end
class LossReport < ActiveRecord::Base
belongs_to :agent
end
J'ai d'abord essayé de remplacer le eql? et la méthode de hachage d'un LossReport pour que je puisse faire quelque chose de similaire à:
Option 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
mais rapidement supprimé le code en raison de ActiveRecord remplaçant déjà les méthodes et mon ne pas être sûr de la répercussions.
Option 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:
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
résultats Benchmark:
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)
Ni chemin fe els droite mais les deux fonctionnent. Quelle est la meilleure option ou existe-t-il un moyen encore meilleur?
ne sais pas pourquoi mais agent.loss_reports (: order => 'created_at desc') n'a pas ordonné les résultats – russellkt
agent.loss_reports (: order => 'created_at desc') n'a pas ordonné les résultats car agent.loss_reports ne l'a pas prendre les mêmes arguments qu'ActiveRecord :: Base.find prend. (Cela prend juste un seul argument booléen: reload (re-run DB query) si vrai.) Utilisez agent.loss_reports.find (: all,: order => 'created_at desc') pour le faire. –