2012-02-06 40 views
1

我試圖構建位居演出在特定事件中的選擇運動員的網站上使用時,目前我的代碼存在問題。有不同的問題結合ORDER

我有2種型號 - AthleteResult(運動員有很多結果)

每個運動員可以有許多的記錄時間爲一個特定的事件,我想找出最快的時間對每個運動員和排列這些最快時間跨越所有運動員。

我使用下面的代碼:

<% @filtered_names = Result.where(:event_name => params[:justevent]).joins(:athlete).order('performance_time_hours ASC').order('performance_time_mins ASC').order('performance_time_secs ASC').order('performance_time_msecs ASC') %> 

這成功地排列所有在所有運動員的成績爲事件(即一個運動員能出現一批依賴於他們所記錄的時間在不同的地方倍) 。

我現在想只拉出最好的結果對於每個運動員,包括他們的排名。我可以選擇的時間對應使用最好的結果:

<% @currentathleteperformance = Result.where(:event_name => params[:justevent]).where(:athlete_id => filtered_name.athlete_id).order('performance_time_hours ASC').order('performance_time_mins ASC').order('performance_time_secs ASC').order('performance_time_msecs ASC').first() %> 

不過,我的問題是當我試圖找出@filtered_names列出的不同運動員的名字。我試着用<% @filtered_names = @filtered_names.select('distinct athlete_id') %>但這並不表現如何我希望它和場合它得到的排名順序錯誤。

我發現,因爲它代表我的代碼基本上會尋找不同的運動員結果之間的差異,先從小時的時間,並通過以分鐘,秒和毫秒進展。一旦發現每個不同運動員的結果之間存在差異,就相應地命令他們。

例如,如果我有2名運動員:

Time for Athlete 1 = 0:0:10:5 
Time for Athlete 2 = 0:0:10:3 

這將產生順序,運動員2,Athlete1

然而,如果我有:

Time for Athlete 1 = 0:0:10:5 
Time for Athlete 2 = 0:0:10:3 
Time for Athlete 2 = 0:1:11:5 

然後順序被給定爲運動員1,運動員2作爲第一個區別是在數字分鐘和運動員2是較慢...

任何人都可以提出一個方法來解決這個問題,基本上是走下來的條目@filtered_names每名拉出它出現在第一時間(即保持名稱的順序,他們第一次出現在@filtered_names

感謝您的時間

回答

1

如果你上紅寶石1.9.2+,您可以使用Array#uniq並傳遞一個塊指定如何確定唯一性。例如:

@unique_results = @filtered_names.uniq { |result| result.athlete_id } 

這應該每個運動員返回結果只有一個,那一個結果應該是數組,這反過來將是最快的時間,因爲你已經下令結果在第一。

一個警告:@filtered_names可能仍然是一個ActiveRecord::Relation,它有自己的#uniq方法。您可能需要先撥打#all返回結果的數組:

@unique_results = @filtered_names.all.uniq { ... } 
+0

布蘭登,非常感謝!使用1.9.2,只是頂部工作完美 – Texas 2012-02-06 06:05:12

+0

任何想法如何在舊版Rails中做到這一點,我認爲我們的主機提供商可能安裝了1.9.0 ...?對不起... – Texas 2012-02-06 06:56:29

+0

哇!我從來沒有真正看到過1.9.0,特別是Rails(如果你使用1.9,我相信Rails需要1.9.2+)。你可以在你的託管服務上運行'ruby -v'來確保?你可能必須實現你自己版本的'#uniq',但是它比原生C中的Ruby實現要慢,這比在數據庫中用SQL執行速度慢,所以要注意這一點。 – Brandan 2012-02-06 14:08:17

0

您應該使用DB來執行計算最大,而不是Ruby代碼。在名爲total_time_in_msecsresults表中添加一個新列,並在每次更改結果表時爲其設置值。

athletes = Athlete.joins(:results). 
    select("athletes.id,athletes.name,max(results.total_time_in_msecs) best_time"). 
    where("results.event_name = ?", params[:justevent]) 
    group("athletes.id, athletes.name"). 
    orde("best_time DESC") 


athletes.first.best_time # prints a number 

寫簡單的輔助,以打破數時部分:

def human_time time_in_msecs 

    "%d:%02d:%02d:%03d" % 
    [Result::MSEC_IN_HOUR, Result::MSEC_IN_MIN, 
     Result::MSEC_IN_SEC, 1 ].map do |interval| 
     r = time_in_msecs/interval 
     time_in_msecs = time_in_msecs % interval 
     r 
    end 

end 

使用助手在你的意見

class Result < ActiveRecord::Base 

    before_save :init_data 

    def init_data 
    self.total_time_in_msecs = performance_time_hours * MSEC_IN_HOUR +  
           performance_time_mins * MSEC_IN_MIN + 
           performance_time_secs * MSEC_IN_SEC + 
           performance_time_msecs 
    end 

    MSEC_IN_SEC = 1000 
    MSEC_IN_MIN = 60 * MSEC_IN_SEC 
    MSEC_IN_HOUR = 60 * MSEC_IN_MIN 
end 

現在你可以寫成如下查詢顯示故障時間。