2012-05-16 40 views
4

。將按'c'升序排列。如何查找散列數組中由多個鍵分組的最大值?具有這種結構的數據有

[ { 'a' => 1, 'b' => 1, 'c' => 1, 'd' => '?' }, 
    { 'a' => 1, 'b' => 1, 'c' => 2, 'd' => '?' }, 
    { 'a' => 1, 'b' => 1, 'c' => 3, 'd' => '?' }, 
    { 'a' => 1, 'b' => 2, 'c' => 4, 'd' => '?' }, 
    { 'a' => 1, 'b' => 2, 'c' => 5, 'd' => '?' }, 
    { 'a' => 2, 'b' => 1, 'c' => 6, 'd' => '?' }, 
    { 'a' => 2, 'b' => 1, 'c' => 7, 'd' => '?' }, 
    { 'a' => 2, 'b' => 1, 'c' => 8, 'd' => '?' }, 
    { 'a' => 2, 'b' => 2, 'c' => 9, 'd' => '?' }, 
    { 'a' => 2, 'b' => 2, 'c' => 10, 'd' => '?' } ] 

想要根據'a'和'b'的每個獨特組合組合'c'的最大值的數組。

[ { 'a' => 1, 'b' => 1, 'c' => 3, 'd' => '?' }, 
    { 'a' => 1, 'b' => 2, 'c' => 5, 'd' => '?' }, 
    { 'a' => 2, 'b' => 1, 'c' => 8, 'd' => '?' }, 
    { 'a' => 2, 'b' => 2, 'c' => 10, 'd' => '?' } ] 

其他鍵需要保留,但與轉換無關。到目前爲止,我能找到的最好方法是顛倒陣列(因此按'c'降序排列),uniq以'a'和'b'排列,然後再顛倒陣列。但我依賴uniq_by的實現始終返回找到的第一個唯一項目。該規範沒有說明,所以我擔心依賴這種行爲,因爲它可能在未來的版本中發生變化。也想知道這是否是一種非常低效的方法。

@data.reverse!.uniq!{|record| [record['a'],record['b']]}.reverse! 

有沒有更好更有效的方法來做到這一點?如果你確實有更好的辦法,你能否請你解釋一下,而不僅僅是給我一個我可能無法破譯的超級討厭的單線程。

回答

10

這實際上是相當容易:

a.group_by { |h| h.values_at("a", "b") }.map { |_, v| v.max_by { |h| h["c"] } } 

或者有更好的格式:

a.group_by do |h| 
    h.values_at("a", "b") 
end.map do |_, v| 
    v.max_by { |h| h["c"] } 
end 

說明:第一,我們使用Enumerable#group_by創建與"a""b"組合一個Hash(與Hash#values_at提取)作爲鍵和所有哈希與該組合作爲值。然後,我們映射這個散列,忽略這些鍵並從Enumerable#max_by中選擇具有"c"的最大值的元素。

+0

您能解釋一下塊參數中'_'的含義嗎? – Flexoid

+3

@Flexoid:沒有特別的意義,它是一個我不關心的參數,並且在很多語言中,通常使用下劃線作爲名稱來表示這一點。 –

+0

@steenslag不知何故''c「'變成了'v',我花了我一秒的時間才知道我在哪兒很蠢;-)重讀我的文字描述有所幫助,因爲我描述得很好...... –

相關問題