Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Provide a proc to a method as a block

Let's say I have the following array:

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

and I want to find the minimum element, comparing the second element of the elements. The minimum element will be [5, 1] since 1 is less than 7. I can use the following code:

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

For calculating the maximum, I can do the same:

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

That gives [2, 7].

I use the same block all the time. I would like to have that block somewhere and provide it to the min/max function. I hoped something like:

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

would work, but it didn't. Any idea on how I can do this?

like image 405
Cristobal Viedma Avatar asked Oct 18 '10 15:10

Cristobal Viedma


3 Answers

A more general solution to problems like this is to avoid nested arrays entirely and use a class instead. You can then define the <=> operator for that class, giving you access to all the functions in the Comparable mixin (http://ruby-doc.org/core/classes/Comparable.html) gives you the <, <=, ==, >=, and > operators and the method 'between?'

This is just an example, in real life you would use classes that describe what they store:

class Duo

  include Comparable

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

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

end

If you have an array of Duo object you can then use the min, max, and sort functions without having to define the comparison operator. So...

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

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

would return the array [ @c, @b, @a ]

And

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

would return @a

This is much more the 'Ruby Way' than nested data-structures with logic that relies on positions in arrays. It takes slightly more work at the start, but you'll find it much better in the long run.

Ruby is a very object oriented programming language and provides very powerful tools for you to use. I thoroughly recommend reading a book like "The Ruby Programming Language" or "The Ruby Way" to get a proper overview of the power of the language.

like image 134
Paul Leader Avatar answered Oct 04 '22 23:10

Paul Leader


Use the & operator to turn a Proc object into a block.

arr.min &blo
like image 24
sepp2k Avatar answered Nov 15 '22 01:11

sepp2k


@sepp2k's answer is the more general one, but in your specific case, I would just use

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

since that is much more obvious than all those curly braces and square brackets and array indices floating around.

like image 14
Jörg W Mittag Avatar answered Nov 15 '22 02:11

Jörg W Mittag