How to restrict an integer to a range in Ruby

If you feel like monkey patching a method, you might do something like this:

class Numeric
  def clamp(min, max)
    self < min ? min : self > max ? max : self
  end
end

# usage
@limit = (params[:limit] || 10).clamp(0, 20)

How about using Enumerable#min, Enumerable#max?

For example, to limit the value in range 0..10:

x = 100
[[10, x].min, 0].max
# => 10

x = -2
[[10, x].min, 0].max
# => 0

x = 5
[[10, x].min, 0].max
# => 5

Alternative, Using Enumerable#sort:

x = 100
[x, 0, 10].sort[1]
# => 10

x = -2
[x, 0, 10].sort[1]
# => 0

x = 5
[x, 0, 10].sort[1]
# => 5

Comparable#clamp is available in Ruby 2.4.

3.clamp(10, 20)
=> 10

27.clamp(10, 20)
=> 20

15.clamp(10, 20)
=> 15

Here is a quick benchmark to show which method we should use. Because someone will inevitably say "Use sort_by because it's faster than sort", I added it. sort_by is only faster than sort when dealing with complex objects. Basic objects, like integers and strings should be handled by sort.

require 'fruity'

class Numeric
  def clamp(min, max)
    self < min ? min : self > max ? max : self
  end
end

compare do
  min_max { [[10, 100].min, 0].max }
  sort { [100, 0, 10].sort[1] }
  sort_by { [100, 0, 10].sort_by{ |v| v }[1] }
  clamp_test { 10.clamp(0, 100) }
  original {
    limit = 10
    limit = 100 if limit > 100
    limit = 0 if limit < 0
    limit
  }
end

With the results being:

Running each test 65536 times. Test will take about 8 seconds.
original is faster than clamp_test by 2x ± 1.0
clamp_test is faster than sort by 6x ± 1.0
sort is faster than min_max by 2x ± 0.1
min_max is faster than sort_by by 2x ± 0.1

Sometimes ugly is better.

Tags:

Ruby