Austin Burke
Austin Burke

Reputation: 148

Can't figure out what the error is with this method?

I'm passing a hash to this function that either a) has keys that are strings along with values that are ints OR b) it is an empty hash. The point of the function is to return nil if the hash is empty and return the key associated with the lowest int.

def key_for_min_value(name_hash)
  if name_hash == nil
    return nil 
  else
   lowest_value = nil
   lowest_value_name = nil
  name_hash.collect do |name, value|
    if lowest_value > value 
      lowest_value = value
      lowest_value_name = name
    end
  end
  return lowest_value_name
 end
end

The error I'm receiving is:

1) smallest hash value does not call the `#keys` method

 Failure/Error: key_for_min_value(hash)

 NoMethodError:
   undefined method `>' for nil:NilClass`

Upvotes: 2

Views: 190

Answers (1)

tadman
tadman

Reputation: 211540

You can't compare nil to anything using >, it's not allowed, so you either have to avoid that test or use tools like min_by to get the right value instead of this collect approach.

One way to make your unit test happy might be:

def key_for_min_value(name_hash)
  return unless (name_hash)

  name_hash.keys.min_by do |key|
    name_hash[key]
  end
end

Ruby leans very heavily on the Enumerable library, there's a tool in there for nearly every job, so when you have some free time have a look around there, lots of things to discover.

Now Ruby is very strict about comparisons, and in particular a nil value can't be "compared" (e.g. > or < and such) to other values. You'll need to populate that minimum with the first value by default, not nil, then the comparisons work out, but doing that completely is pretty ugly:

def key_for_min_value(name_hash)
  return unless (name_hash)

  min_key, min_value = name_hash.first

  name_hash.each do |key, value|
    next unless (value < min_value)

    min_key = key
    min_value = value
  end

  min_key
end

So that approach is really not worth it. Enumerable makes it way easier and as a bonus your intent is clear. One thing you'll come to appreciate is that in Ruby if your code looks like code then you're probably going about it the wrong way, over-complicating things.

Ruby is an unusually expressive language, and often there's a very minimal form to express just about anything.

Upvotes: 4

Related Questions