Предоставить метод в качестве блока - PullRequest
11 голосов
/ 18 октября 2010

Допустим, у меня есть следующий массив:

arr = [[5, 1], [2, 7]]

и я хочу найти минимальный элемент, сравнивая второй элемент из элементов. Минимальный элемент будет [5, 1], поскольку 1 меньше 7. Я могу использовать следующий код:

arr.min {|a,b| a[1] <=> b[1]}

Для расчета максимума я могу сделать то же самое:

arr.max {|a,b| a[1] <=> b[1]}

Это дает [2, 7].

Я все время использую один и тот же блок. Я хотел бы иметь этот блок где-нибудь и предоставить его функции min / max. Я надеялся что-то вроде:

blo = lambda {|a,b| a[1] <=> b[1]}
arr.min blo

будет работать, но это не так. Любая идея о том, как я могу это сделать?

Ответы [ 5 ]

24 голосов
/ 18 октября 2010

Используйте оператор &, чтобы превратить объект Proc в блок.

arr.min &blo
14 голосов
/ 18 октября 2010

@ sepp2k - более общий ответ, но в вашем конкретном случае я бы просто использовал

arr.min_by(&:last)
arr.max_by(&:last)

, поскольку это намного более очевидно, чем все эти фигурные скобки, квадратные скобки и индексы массивов, плавающие вокруг.

3 голосов
/ 18 октября 2010

Если все, что вам нужно, это минимум и максимум, вы можете использовать метод Enumerable#minmax и рассчитать оба сразу:

min, max = arr.minmax {|a,b| a[1] <=> b[1]}
#=> [[5, 1], [2, 7]]
min
#=> [5, 1]
max
#=> [2, 7]

Редактировать: Ад, я только что заметил, что естьтакже minmax_by, так что вы можете комбинировать его с методом last и иметь:

min, max = arr.minmax_by &:last
2 голосов
/ 18 октября 2010

как насчет этого?

=> [[5, 4], [9, 5], [2, 7]]
>> arr.sort!{|x,y| x[1]<=>y[1] }
=> [[5, 4], [9, 5], [2, 7]]
>> min,max=arr[0],arr[-1]
=> [[5, 4], [2, 7]]
1 голос
/ 18 октября 2010

Более общее решение таких проблем состоит в том, чтобы полностью избегать вложенных массивов и использовать вместо них класс. Затем вы можете определить оператор <=> для этого класса, предоставляя вам доступ ко всем функциям в Comparable mixin (http://ruby -doc.org / core / classes / Comparable.html) дает вам <, <=, = =,> = и> операторы и метод 'Между?'

Это всего лишь пример, в реальной жизни вы бы использовали классы, которые описывают то, что они хранят:

class Duo

  include Comparable

  def initialize( a, b )
      @a = a
      @b = b
  end

  def <=>(rhs)
      @b <=> rhs.b
  end

end

Если у вас есть массив объектов Duo, вы можете использовать функции min, max и sort без определения оператора сравнения. Итак ...

@a = Duo.new( 1, 10 )
@b = Duo.new( 2, 5 )
@c = Duo.new( 3, 1 )

[ @a, @b, @c ].sort

вернет массив [@c, @b, @a]

И

[@a, @b, @c].max

вернется @a

Это гораздо больше "Ruby Way", чем вложенные структуры данных с логикой, которая опирается на позиции в массивах. На старте требуется немного больше работы, но в долгосрочной перспективе это будет намного лучше.

Ruby является очень объектно-ориентированным языком программирования и предоставляет вам очень мощные инструменты. Я настоятельно рекомендую прочитать книгу типа «Язык программирования Ruby» или «The Ruby Way», чтобы получить полное представление о возможностях языка.

...