如何将自定义比较器传递给“排序”?

A类有以下比较器:

 class A attr_accessor x def my_comparator(a) x**2  (ax)**2 end end 

我想使用这个比较器对每个项目属于A类的数组进行排序:

 class B def my_method items.sort!() end end 

我应该如何通过my_comparator进行sort!

定义您自己的<=> ,并包括Comparable。 这来自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] 

您实际上不必包含Comparable,但如果您在定义<=>后执行此操作,则可以免费获得额外的function。

否则,如果对象已经实现<=> ,则可以sort块使用Enumerable的sort

编辑:使用几种不同比较的另一种方法是使用lambda。 这使用新的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] 

这两个都应该工作:

 items.sort_by! { |a| (ax)**2 } items.sort! { |a1,a2| a1.my_comparator(a2) } 
 items.sort!(&:my_comparator) 

这会在内部调用:my_comparator.to_proc ,它返回一个块

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

从而减少了对Ben Alpert答案的答案。

(但我同意Phrogz的观察,如果这是课堂的自然顺序,那么你应该使用Tin Man的答案。)

如果要在不同的地方重用这些比较器,最好将它们定义为类,而不是每次都重写相同的lambda表达式。

这是基于Java的Comparable接口的实现:

 module Comparator def compare(a, b) raise NotImplementedError, 'must implement this method' end def to_proc ->(a, b) { compare(a, b) } end end class LengthComparator include Comparator def compare(a, b) a.length <=> b.length end end class ReverseLengthComparator < LengthComparator def compare(a, b) -super end end 

您可以在#compare方法中实现比较逻辑。 然后你就可以像这样使用这个类: array.sort(&MyCustomComparator.new) 。 它基本上归结为lambda表达式,但在我看来支持更多的可重用性。