2011-08-24 63 views
2

比方說,有是一個字符串數組的數組:紅寶石:以獨特的子陣列相對於一個特定領域

array = [["John","Apples"],["Tim","Apples"],["Frank","Apples"], 
    ["Tom","Pears"],["John","Pears"],["Frank","Oranges"],["Tim","Oranges"]] 

現在的遊戲是要選擇那些對數組的第二獨特價值的任何記錄以一種簡單的方式,例如結果可能是:

array2 = [["Frank","Apples"],["Tom","Pears"],["Tim","Oranges"]] 

有沒有人知道是否有這樣的單線程?

+2

我喜歡這個遊戲。發佈了很多聰明的答案。 –

回答

6

Array#uniq可以採取塊參數:

array.uniq { |e| e[1] } 

例如:

>> array = [["John","Apples"], ["Tim","Apples"], ["Frank","Apples"], ["Tom","Pears"], ["John","Pears"], ["Frank","Oranges"], ["Tim","Oranges"]] 
>> array.uniq { |e| e[1] } 
=> [["John", "Apples"], ["Tom", "Pears"], ["Frank", "Oranges"]] 

你可能會率先拿到賽(而不是最後一次爲你「可以是」輸出),但我不認爲有任何保證哪個一個會被選中。

注意,在1.9這個唯一的作品,1.8不喜歡它,所以你必須在1.8更加努力地工作,但不是更難:

array.inject({ }) { |h,e| h[e[1]] = e[0]; h }.map { |k,v| [ v, k ] } 

inject/map版本的工作原理相同的1.8和1.9。此外,這一個挑選最後的重複值。

+1

注意:不能在紅寶石中工作1.8 –

+1

@nash:謝謝,我會添加一個免責聲明。幾個月後我沒有碰到1.8。 –

3

在Ruby 1.8:

array.map{ |k,v| v }.uniq.map{ |uv| array.select{ |k,v| v == uv }.last } 

Hash[*array.map{ |k,v| [v,k] }.flatten].map{ |k,v| [v,k] } 

[更新: 「萬畝太短」 給了一個很好的答案爲Ruby 1.9,上面的答案我給了有利於紅寶石1.8]

+0

+1對1.8的解決方案。 –

5

另一種解決方案應該在1.8和1.9工作:

array.group_by(&:last).map { |k,v| v.last } 
# => [["John", "Pears"], ["Frank", "Apples"], ["Tim", "Oranges"]] 
+0

我有'group_by'的盲點,我一直忘記它存在。 –

+2

@mu太短了:我真的很喜歡這種方法,我已經多次派上用場了:-) –

+0

出於某種原因,我一直認爲「group_by」是一種有效的支持方法,所以在編寫普通的ruby時我從未使用它。去搞清楚。 –

3

facets寶石器具(除一個巨大的其他有用的方法量)的uniq_by方法:

module Enumerable 
    def uniq_by #:yield: 
    h = {}; inject([]) {|a,x| h[yield(x)] ||= a << x} 
    end 
end