476

I want to use min(5,10), or Math.max(4,7). Are there functions to this effect in Ruby?

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
obuzek
  • 4,933
  • 2
  • 18
  • 6

5 Answers5

826

.min

[5, 10].min

.max

[4, 7].max

They come from the Enumerable module, so anything that includes Enumerable will have those methods available.

v2.4 introduces own Array#min and Array#max, which are way faster than Enumerable's methods because they skip calling #each.

.minmax

@nicholasklick mentions another option, Enumerable#minmax, but this time returning an array of [min, max].

[4, 5, 7, 10].minmax
#=> [4, 10]
Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
theIV
  • 25,434
  • 5
  • 54
  • 58
  • Don't forget to sanitize the array first by removing nil values, or values that cannot be compared – Cyril Duchon-Doris Jun 15 '15 at 22:02
  • 10
    Ruby is mainly for the programmer not for the computer. In Matz's words "I hope to see Ruby help every programmer in the world to be productive, and to enjoy programming, and to be happy. That is the primary purpose of Ruby language." That's from the Wikipedia page on Ruby. – aaron-coding Nov 02 '15 at 23:42
  • @aaron-coding Well, helping the programmer to write inefficient code isn't exactly helping him. ;) But yes - I know in _many_ cases these micro-optimizations don't matter. However, I think there is an underlying problem in Ruby encouraging inefficiency. Efficiency is not Ruby's greatest strength or design goal; it has other, more eloquent values. – Per Lundberg Oct 31 '17 at 09:31
  • Am I wrong, or does @nicholasklick not exist any more? I wanted to link him, but weren't able to find him. – Cadoiz Dec 16 '22 at 07:23
  • 1
    The existence of `.minmax` is yet another reason why I love Ruby. – Joshua Pinter May 24 '23 at 19:26
59

You can use

[5,10].min 

or

[4,7].max

It's a method for Arrays.

slhck
  • 36,575
  • 28
  • 148
  • 201
Diego Dias
  • 21,634
  • 6
  • 33
  • 36
32

If you need to find the max/min of a hash, you can use #max_by or #min_by

people = {'joe' => 21, 'bill' => 35, 'sally' => 24}

people.min_by { |name, age| age } #=> ["joe", 21]
people.max_by { |name, age| age } #=> ["bill", 35]
aaron-coding
  • 2,571
  • 1
  • 23
  • 31
32

All those results generate garbage in a zealous attempt to handle more than two arguments. I'd be curious to see how they perform compared to good 'ol:

def max (a,b)
  a>b ? a : b
end

which is, by-the-way, my official answer to your question.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Dave Morse
  • 717
  • 9
  • 16
  • There's some rumblings that Ruby 2.4 is optimizing `[a,b].max`, but it's still not clear if it's faster than the above implementation. http://blog.bigbinary.com/2016/11/17/ruby-2-4-implements-array-min-and-max.html – Dave Morse May 26 '17 at 21:48
  • 3
    this is micro-optimization, they're both so fast, the difference is negligible, see benchmark: https://repl.it/@AndreFigueiredo/DearWeirdSweepsoftware – Andre Figueiredo Jul 03 '18 at 06:11
  • 3
    Does this profiling take into account the time spent in GC? – Dave Morse Jul 06 '18 at 14:33
21

In addition to the provided answers, if you want to convert Enumerable#max into a max method that can call a variable number or arguments, like in some other programming languages, you could write:

def max(*values)
 values.max
end

Output:

max(7, 1234, 9, -78, 156)
=> 1234

This abuses the properties of the splat operator to create an array object containing all the arguments provided, or an empty array object if no arguments were provided. In the latter case, the method will return nil, since calling Enumerable#max on an empty array object returns nil.

If you want to define this method on the Math module, this should do the trick:

module Math
 def self.max(*values)
  values.max
 end
end

Note that Enumerable.max is, at least, two times slower compared to the ternary operator (?:). See Dave Morse's answer for a simpler and faster method.

Community
  • 1
  • 1
HamsterMuffin
  • 33
  • 1
  • 7