Home > OS >  Categorizing a number based on ranges
Categorizing a number based on ranges

Time:06-17

I have some ranges defined:

very_low = <10
low = 11-20
medium = 21-30
high = 31-40
very_high = 41 

What is the most succinct way in Ruby to find out which category any given number is in?

e.g know that 23 would be 'medium'

CodePudding user response:

I would do:

RANGES = {
  very_low:    (..10),
  low:       (11..20),
  medium:    (21..30),
  high:      (31..40),
  very_high: (41..)
}

def range_for(number)
  RANGES.find { |_, range| range.cover?(number) }.first
end

range_for(23)
#=> :medium

It uses Enumerable#find with Range#cover? to pick the matching range definition. The find method returns an array including both, key and value. The chained first call then picks the key from the array which will be the requested range identifier.

CodePudding user response:

you've changed your question, but you now have overlaps (40, and 40 ) ... I don't know if you're working with integers or decimals, but I'm assuming integers because you're not dealing with "10" or "10.5" ... how about this:

def which_range? num
  ranges={
    very_low: (..10),
    low: (11..20),
    medium: (21..30),
    high: (31..40),
    very_high: (41..)
  }
  ranges.each do |key,val|
    return key if val.include?(num)
  end
  return false
end

example output:

2.7.2 :073 > which_range? 23
 => :medium
2.7.2 :074 > which_range? 7
 => :very_low
2.7.2 :075 > which_range? 25
 => :medium
2.7.2 :076 > which_range? 35
 => :high
2.7.2 :077 > which_range? 45
 => :very_high
2.7.2 :123 > which_range? 102
 => :very_high
2.7.2 :124 > which_range? -12
 => :very_low

CodePudding user response:

If I get your question correctly, then, perhaps, case statement is something you looking for

case some_number
when ..10 then 'very_low'
when 11..20 then 'low'
when 40.. then 'very_high'
...
end

# P.S.: for older versions without endless ranges:

case some_number
when -Float::INFINITY..10 then 'very_low'
when 11..20 then 'low'
when 40..Float::INFINITY then 'very_high'
...
end


CodePudding user response:

Assuming the ranges are consecutive, you could define the upper or lower bounds in an array in order from low to high (when using upper bounds) or from high to low (when using lower bounds). Then have an array with their respective name at the same index.

def range_name(number)
  range_names  = ['very_low', 'low', 'medium', 'high',   'very_high'  ]
  upper_bounds = [    10    ,   20 ,    30   ,   40  , Float::INFINITY] # inclusive

  index = upper_bounds.find_index { |upper_bound| number <= upper_bound }

  range_names[index]
end
  •  Tags:  
  • ruby
  • Related