1

I have four sizes, each are in a hash by their square feet:

# The sizes. Sizes are in sq ft (min, max)
size_hash = {
  'Large'  => [70,139],
  'Medium' => [15,69],
  'Small'  => [1,14]
}

If I'm given the number 40, how can I return Medium as the size from the array?

Do I need to do something like this?:

# The sizes. Sizes are in sq ft (min, max)
size_hash = {
  [70..139]  => 'Large',
  #... etc
}
1
  • In the future, if you have a data structure but are open to changing it, you might make that clear. :) Commented Nov 25, 2012 at 4:58

4 Answers 4

5

You could use a proc:

size_store = proc{ |n|
  case n
  when 70..139
    'Large'
  when 15..69
    'Medium'
  when 1..14
    'Small'
  end
}
# USAGE: size_store[40]
Sign up to request clarification or add additional context in comments.

2 Comments

Why use a proc instead of a basic method ?
Depends on the circumstances. It's got no method dispatch and is used with [],like a hash. E.g. if it gets called often, I would probably initialize an array with the data or use Hash.new with a default proc. If it's part of the behavior of an object, I would put it in a method as well.
4
size_hash.find{|_, (min, max)| (min..max) === 40}[0]
# => "Medium"

But I think it is a better idea to store ranges instead of min and max in the first place.

size_hash = {
    'Large'  => 70..139,
    'Medium' => 15..69,
    'Small'  => 1..14,
}

size_hash.find{|_, r| r === 40}[0]
# => "Medium"

Comments

2

Yet another solution taking care of edge cases ...

@size_hash = {
  'Large'  => 70..139,
  'Medium' => 15..69,
  'Small'  => 1..14,
}

some_value = @size_hash["Small"]
@min = some_value.first
@max = some_value.last
@size_hash.each_pair do |k, v|
    @min = [@min, v.first].min
    @max = [@max, v.last].max
end

puts "size_hash goes from #{@min} to #{@max}"

    # Given a number, return the name of the range which it belongs to.
def whichSize(p_number)
    @size_hash.each_pair do |k, v|
        return k if v.include?(p_number)
    end

    return "below minimum" if p_number < @min
    "above maximum" if p_number > @max
end

# test
[-10, 0, 1, 10, 14, 15, 20, 69, 70, 80, 139, 140, 1000].each do |e|
    puts "size of #{sprintf("%4s", e)} is #{whichSize(e)}"
end

$ ruby -w t.rb 
size_hash goes from 1 to 139
size of  -10 is below minimum
size of    0 is below minimum
size of    1 is Small
size of   10 is Small
size of   14 is Small
size of   15 is Medium
size of   20 is Medium
size of   69 is Medium
size of   70 is Large
size of   80 is Large
size of  139 is Large
size of  140 is above maximum
size of 1000 is above maximum

Comments

1

If you stored ranges as keys, you could do this:

size_hash = Hash.new {|hash, key| hash.find {|range,_| range.cover?(key) }.last }.merge({
  (1..14)   => 'Small',
  (15..69)  => 'Medium',
  (70..139) => 'Large'
})

This sets a default proc in the hash, so when you look up a value, like size_hash[9], the first range covering that value is returned. Bear in mind that this doesn't handle out-of-range errors.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.