Подтвердить что ты не робот

Как передать пользовательский компаратор для сортировки?

Класс 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_comparator в sort!?

4b9b3361

Ответ 1

Определите свой собственный <=> и включите Comparable. Это из Сопоставимый документ:

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, но вы получаете дополнительную функциональность бесплатно, если вы это сделаете после определения <=>.

В противном случае вы можете использовать Enumerable sort с блоком, если ваши объекты уже реализуют <=>.

EDIT: Другой способ использовать несколько разных сравнений - использовать лямбда. Это использует новый синтаксис объявления 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]

Ответ 2

Оба они должны работать:

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

Ответ 3

items.sort!(&:my_comparator)

Это вызывает внутри :my_comparator.to_proc, который возвращает блок

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

таким образом уменьшая этот ответ до ответа Бен Алперта.

(Но я согласен с наблюдением Фрогца, что если это естественный порядок для класса, то вместо этого вы должны использовать ответ Tin Man.)