2011-01-07 23 views
25

Sınıf A aşağıdaki karşılaştırıcı vardır:Özel bir karşılaştırıcı nasıl "sort" için geçirilir?

class A 
    attr_accessor x 

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

Her öğe sınıflandırma A'nın bir dizi sıralamak için bu karşılaştırıcı kullanmak istiyorum:

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

nasıl sort! için my_comparator geçmesi gerekir?

+1

Gerçekten, sen 'items.sort kullanabilirsiniz! {| x, y | x.my_comparator y} ', ama bu Tin Man aşağıda neler gibi bir şey düşünmelisiniz sınıf için varsayılan sıralama davranıştır eğer. – coreyward

cevap

33

<=> kendi tanımlayın ve Karşılaştırılabilir sayılabilir.

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] 

Aslında Karşılaştırılabilir dahil etmek gerekmez, ancak <=> belirlendikten sonra bunu yaparsan ücretsiz ekstra işlevsellik olsun: Bu Comparable doc değil. Nesnelerinizin zaten <=> uygularsanız

Aksi takdirde, bir blok ile Enumerable's sort kullanabilirsiniz.

DÜZENLEME: birkaç farklı karşılaştırmalar kullanmanın bir başka yolu lambdas kullanmaktır. Bu yeni 1.9.2 beyan sözdizimini kullanır:

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] 
+1

Veya, bu soruya spesifik: 'alias_method: <=>: my_comparator' – Phrogz

+0

1. İyi yakalamak @Phrogz, ilk etapta yöntemi '<=>' çağırmak için daha Yakut-imsi olacağını bile. Benim durumumda –

+0

, birkaç karşılaştırıcılara var, bu yüzden my_comparator' 'ile' '<=> geçersiz kılmak istemiyoruz. –

16

Bunların her ikisi de çalışması gerekir:

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

Bu iyi ve doğru, ancak @TinMan'ın cevabı özel sınıflar için daha iyidir. – Phrogz

+0

Aradığım cevap buydu, OO orayı mahvetmek değil. –

5
items.sort!(&:my_comparator) 

Bu içten :my_comparator.to_proc çağırır, böylece Ben Alpert cevabı bu cevabı azaltan bir blok

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

döndürür.

(Ama bu sınıf için doğal dereceden ise, o zaman bunun yerine Tin Man cevabı kullanması gerektiğini Phrogz gözlemiyle hemfikirler.)

İlgili konular