Question

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?

Was it helpful?

Solution

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

arr.min &blo

OTHER TIPS

@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.

If all that you need is minimum and maximum, you might use Enumerable#minmax method and calculate both at once:

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

Edit: Hell, I just noticed there is also minmax_by, so you can combine it with last method, and have:

min, max = arr.minmax_by &:last

how about this?

=> [[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]]

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top