Reputation: 23
I am trying to create a function that takes a string in it's parameters. It's supposed to determine the highest and lowest numeric values in the string and return them unchanged. Here's my code:
def high_and_low(numbers)
numbers.split
numbers.each {|x| x.to_i}
return numbers.max().to_s, numbers.min().to_s
end
Here's the error:
main.rb:5:in `high_and_low': undefined method `each' for "4 5 29 54 4 0 -214 542 -64 1 -3 6 -6":String (NoMethodError)
from main.rb:8:in `<main>'
Upvotes: 0
Views: 75
Reputation: 30453
You have not changed the value from string to array.
Replace numbers.split
with numbers = numbers.split
.
Also you will need to change from numbers.each { |x| x.to_i }
to numbers.map!(&:to_i)
. Otherwise you don't save integers anywhere.
BTW you don't have to use ()
and return
(if it's in the end) so you can write [numbers.max.to_s, numbers.min.to_s]
.
Something like this should work:
def high_and_low(numbers)
numbers = numbers.split.map(&:to_i)
[numbers.max, numbers.min].map(&:to_s)
end
high_and_low("4 5 29 54 4 0 -214 542 -64 1 -3 6 -6") #=> ["542", "-214"]
And bonus (one liner, not that you should write code this way):
def high_and_low(numbers)
numbers.split.map(&:to_i).sort.values_at(-1, 0).map(&:to_s)
end
high_and_low("4 5 29 54 4 0 -214 542 -64 1 -3 6 -6") #=> ["542", "-214"]
The other answer is a good approach too so I include it here:
numbers.split.minmax_by { |n| -n.to_i }
Upvotes: 1
Reputation: 160551
Ruby has some nice methods available to make this much more simple:
"2 1 0 -1 -2".split.map(&:to_i).minmax
# => [-2, 2]
Breaking it down:
"2 1 0 -1 -2".split # => ["2", "1", "0", "-1", "-2"]
.map(&:to_i) # => [2, 1, 0, -1, -2]
.minmax # => [-2, 2]
If you want string versions of the values back, compare two integers in a block. minmax
will return the values at the corresponding positions in the source array:
"2 1 0 -1 -2".split.minmax{ |a, b| a.to_i <=> b.to_i }
# => ["-2", "2"]
or:
"2 1 0 -1 -2".split.minmax_by{ |a| a.to_i }
# => ["-2", "2"]
minmax
and minmax_by
do the heavy lifting. The first is faster when there isn't a costly lookup to find the values being compared such as this case where the values are in an array and only needed to_i
to compare them.
The *_by
version performs a "Schwartzian transform" which basically remembers the values in the block as they're compared so the costly lookup only occurs once. (Many of Enumerable's methods have *_by
versions.) These versions of the methods can improve the speed when you want to compare two values that are nested, perhaps in arrays of hashes of hashes, or objects within objects within objects.
Note: When comparing string versions of numbers it's important to convert to a numeric value when comparing. ASCII and strings order differently than numbers, hence the use of to_i
.
Upvotes: 0