454

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

the Tin Man
  • 155,156
  • 41
  • 207
  • 295
obuzek
  • 4,713
  • 2
  • 16
  • 6

6 Answers6

790

You can do

[5, 10].min

or

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

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

[4, 5, 7, 10].minmax
=> [4, 10]
the Tin Man
  • 155,156
  • 41
  • 207
  • 295
theIV
  • 24,904
  • 5
  • 52
  • 57
  • Thanks @nicholasklick, just updated my answer. Didn't even know that existed! – theIV Apr 30 '13 at 16:48
  • Common Lisp: `(defun minmax (&rest args) (values (apply #'min args) (apply #'max args)))` Now: `(minmax 3 4 5 7 1 9 2)` yields two return values, 1 and 9. – Kaz Feb 22 '14 at 08:20
  • 3
    @kaz I'm not sure I understand your comment. – Ziggy Feb 23 '14 at 15:41
  • 3
    @Kaz ...you realize `std::max(4, 7)` has more "punctuation" than `[4, 7].max`? – tckmn Mar 24 '14 at 22:51
  • 3
    @Doorknob You do realize that `std::max` can be imported into your namespace so it just becomes `max(4, 7)`. Wait; looking above, I see I said that already. – Kaz Mar 25 '14 at 01:03
  • 3
    @Kaz Okay, so the same amount of punctuation then. In any case, my point is that "punctuation" is not a valid metric for anything. – tckmn Mar 25 '14 at 01:07
  • 23
    Punctuation isn't the problem here. An entire heap allocation to get the max of a few values is the underlying ugliness here. – kdbanman Mar 07 '15 at 21:37
  • 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
  • 9
    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
  • @Kaz Nice Common Lisp algorithm, but inefficient. – Fernando Pelliccioni Jul 05 '19 at 19:42
58

You can use

[5,10].min 

or

[4,7].max

It's a method for Arrays.

slhck
  • 33,914
  • 26
  • 134
  • 182
Diego Dias
  • 20,439
  • 5
  • 31
  • 35
31

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
  • 155,156
  • 41
  • 207
  • 295
Dave Morse
  • 679
  • 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
  • 2
    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
  • 2
    Does this profiling take into account the time spent in GC? – Dave Morse Jul 06 '18 at 14:33
28

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,423
  • 21
  • 31
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
-3
def find_largest_num(nums)
  nums.sort[-1]
end
Almokhtar
  • 70
  • 1
  • 9