Каков наилучший способ получить уникальные элементы массива объектов activerecord на основе атрибутов объекта? - PullRequest
1 голос
/ 14 января 2010

В моем приложении я пытаюсь отобразить только уникальные элементы массива объектов activerecord (loss_reports) на основе двух атрибутов loss_report.

Схема

class Agent < ActiveRecord::Base
  has_many :loss_reports, :through => policy  
end

class LossReport < ActiveRecord::Base
  belongs_to :agent  
end

Я впервые попытался переопределить eql? и метод хеширования в LossReport, чтобы я мог сделать что-то похожее на:

Вариант 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

, но быстро удалил код из-за того, что ActiveRecord уже переопределил методы и я не был уверен в последствиях.

Вариант 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  

Вариант 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.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)

Никто не чувствует себя хорошо, но оба работают. Какой вариант лучше или есть еще лучший способ?

1 Ответ

1 голос
/ 14 января 2010

Я не имею представления о тестах, но кажется, что inject будет самым простым способом:

loss_reports.inject([]) do |arr, report|
  arr << report unless arr.detect{|r| ... } 
end

Или, может быть, еще лучше определить named_scope с пользовательской группой SQL с помощью ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...