如何将自定义比较器传递给“排序”?
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表达式,但在我看来支持更多的可重用性。