2011-01-07 70 views
25

A具有以下比較:如何將自定義比較器傳遞給「排序」?

class A 
    attr_accessor x 

    def my_comparator(a) 
    x**2 <=> (a.x)**2 
    end 
end 

我想用這個比較排序數組,其中每個產品A類:

class B 
    def my_method 
    items.sort!(<how can I pass my_comparator here ?>) 
    end 
end 

我應該如何通過my_comparatorsort!

+1

從字面上看,你可以使用`items.sort! {| x,y | x.my_comparator y}`,但如果這是該類的默認排序行爲,則應該考慮類似Tin Man所具有的內容。 – coreyward 2011-01-07 03:46:18

回答

33

定義自己的<=>,幷包括相媲美。這是從Comparable doc

class SizeMatters 
    include Comparable 
    attr :str 
    def <=>(anOther) 
    str.size <=> anOther.str.size 
    end 
    def initialize(str) 
    @str = str 
    end 
    def inspect 
    @str 
    end 
end 

s1 = SizeMatters.new("Z") 
s2 = SizeMatters.new("YY") 
s3 = SizeMatters.new("XXX") 
s4 = SizeMatters.new("WWWW") 
s5 = SizeMatters.new("VVVVV") 

s1 < s2      #=> true 
s4.between?(s1, s3)   #=> false 
s4.between?(s3, s5)   #=> true 
[ s3, s2, s5, s4, s1 ].sort #=> [Z, YY, XXX, WWWW, VVVVV] 

你實際上並不包括相媲美,但你會得到額外的功能爲免費的,如果你這樣做後具有確定的<=>

否則,如果您的對象已實現<=>,則可以使用Enumerable's sort和塊。

編輯:使用幾個不同比較的另一種方法是使用lambdas。這使用了新的1.9.2聲明語法:

ascending_sort = ->(a,b) { a <=> b } 
descending_sort = ->(a,b) { b <=> a } 

[1, 3, 2, 4].sort(& ascending_sort) # => [1, 2, 3, 4] 
[1, 3, 2, 4].sort(& descending_sort) # => [4, 3, 2, 1] 

foo = ascending_sort 
[1, 3, 2, 4].sort(& foo) # => [1, 2, 3, 4] 
16

這兩個應該工作:

items.sort_by! { |a| (a.x)**2 } 
items.sort! { |a1,a2| a1.my_comparator(a2) } 
+0

這是很好的和正確的,但@TheTinMan的答案更適合自定義類。 – Phrogz 2011-01-07 03:29:17

+0

這是我正在尋找的答案,不是那個OO廢話。 – 2017-05-17 22:44:46

5
items.sort!(&:my_comparator) 

這將調用:my_comparator.to_proc內部,它返回一個塊

proc {|x,y| x.my_comparator(y)} 

從而降低這個答案本阿爾珀特的答案。

(但我Phrogz的觀察,如果這是自然爲了類,那麼你應該用鐵皮人的答案,而不是同意。)

相關問題