Extract and multiple integers from user-input string in Ruby? - ruby

I want to take multiple integer inputs in same line
eg :- input
-1 -1
500 500
so that I can multiply them. I am taking the input in a string from keyboard - then what should I do?

This prints ["5", "66", "7", "8"] if you type a line containing 5 66 7 8 (separated by any whitespace):
p $stdin.readline.split
To get them multiplied, do something like this:
q = 1
$stdin.readline.split.each {|n| q *= n.to_i }
p q

Or you could use String#scan:
irb> "input -1 -1 500 500".scan(/[+-]?\d+/).map { |str| str.to_i }
#=> [-1, -1, 500, 500 ]

array = input.split(' ')
or, if you're entering them as command line parameters, just use the ARGV array

Related

Find the smallest 4-digit number that decreases by 27 when you move its last digit to the first position. (Use the find or detect method) in Ruby

I'm trying to run standard ruby training programs, but I had a problem with this program, please take a look. Thank you very much!
Code:
q = 9999 #last 4-digit number
while q > 1000 #from 9999 to 1000, for exemple, the cycle has arrived to 6784
d = q.to_s.chars.map(&:to_i) #transform 6784 to array [6, 7, 8, 4]
p = d # create sample array with [6, 7, 8, 4]
tmp = p[0]; # tmp = 6;
p[0] = p[3]; # 6 = 4;
p[3] = tmp; # 4 = 6
g = p.join.to_i # transform [4, 7, 8, 6] to 4786
f = q - g # 6784 - 4786
if f == 27 # i need to find the smallest 4-digit number that decreases by 27 when moving its last digit to the first position
puts q #print 4-digit number that decreases by 27 when moving its last digit to the first position
end
q = q - 1;
end
But the result does not appear, it is because it is not, or somewhere a mistake.
In general, the condition of the task is:
Find the smallest 4-digit number that decreases by 27 when you move its last digit to the first position. (Use the find or detect method). Thank You!
I will first create a helper method to convert an array of digits to an integer.
def digits_to_int(arr)
arr.reduce { |n,d| n*10 + d }
end
For example,
digits_to_int [1,2,3,4]
#=> 1234
This tends to be faster than arr.join.to_i (see sawa's answer here).
We can then simply compute
(1..).find { |n| n-27 == digits_to_int(n.digits.rotate.reverse) }
#=> 30
See Enumerable#reduce (a.k.a. inject), "Endless range", Integer#digits, Array#rotate and Array#reverse.
Here is an example calculation.
n = 243
a = n.digits
#=> [3,4,2]
b = a.rotate
#=> [4,2,3]
c = b.reverse
#=> [3,2,4]
d = digits_to_int(c)
#=> 324
n - 27 == d
#=> 243 - 27 == 324 => false
and another
n = 30
a = n.digits
#=> [0,3]
b = a.rotate
#=> [3,0]
c = b.reverse
#=> [0,3]
d = digits_to_int(c)
#=> 3
n - 27 == d
#=> 30 - 27 == 3 => true
I would define a method to "rotate" the number using string manipulation.
def rotate_number_one_digit(n)
s = n.to_s
"#{s[-1]}#{s[0..-2]}".to_i
end
Then I would use #upto to deal with the iteration.
1000.upto(9999) do |x|
end
Each time around you'll check that the "rotated" number plus 27 equals x. If so, print it and break the loop to prevent further unnecessary iteration.
1000.upto(9999) do |x|
if rotate_number_one_digit(x) + 27 == x then
puts x
break
end
end
Or we can just use the #find method from Enumerable.
1000.upto(9999).find { |x| rotate_number_one_digit(x) + 27 == x }
Or using break to return a value from the loop.
1000.upto(9999) { |x|
break x if rotate_number_one_digit(x) + 27 == x
}

Returning the highest and lowest numbers in a string: Ruby

Not sure what I'm doing incorrect but I seem to be getting it woefully wrong.
The question is, you are given a string of space separated numbers, and have to return the highest and lowest number.
Note:
All numbers are valid Int32, no need to validate them.
There will always be at least one number in the input string.
Output string must be two numbers separated by a single space, and highest number is first.
def high_and_low(numbers)
# numbers contains a string of space seperated numbers
#return the highest and lowest number
numbers.minmax { |a, b| a.length <=> b.length }
end
Output:
`high_and_low': undefined method `minmax' for "4 5 29 54 4 0 -214 542 -64 1 -3 6 -6":String
minmax is not implemented for a string. You need to split your string into an array first. But note that split will return an array of strings, not numbers, you will need to translate the strings to integers (to_i) in the next step.
Because minmax returns the values in the opposite order than required, you need to rotate the array with reverse and then just join those numbers with whitespace for the final result.
numbers = "4 5 29 54 4 0 -214 542 -64 1 -3 6 -6"
def high_and_low(numbers)
numbers.split.minmax_by(&:to_i).reverse.join(' ')
end
high_and_low(numbers)
#=> "542 -214"
How about:
numbers_array = numbers.split(' ')
"#{numbers_array.max} #{numbers_array.min}"
If you're starting with a string of numbers you may have to cast the .to_i after the call to split.
In that case:
numbers_array = numbers.split(' ').map { |n| n.to_i }
"#{numbers_array.max} #{numbers_array.min}"
As you're starting with a String, you must turn it into an Array to cast minmax on it.
Also, make sure to compare Integers by casting .map(&:to_i) on the Array; otherwise you'd compare the code-point instead of the numerical value.
def get_maxmin(string)
string.split(' ')
.map(&:to_i)
.minmax
.reverse
.join(' ')
end
There is no need to convert the string to an array.
def high_and_low(str)
str.gsub(/-?\d+/).
reduce([-Float::INFINITY, Float::INFINITY]) do |(mx,mn),s|
n = s.to_i
[[mx,n].max, [mn,n].min]
end
end
high_and_low "4 5 29 54 4 0 -214 542 -64 1 -3 6 -6"
#=> [542, -214]
Demo
This uses the form of String#gsub that has one argument and no block, so it returns an enumerator that I've chained to Enumerable#reduce (a.k.a. inject). gsub therefore merely generates matches of the regular expression /-?\d+/ and performs no substitutions.
My solution to this kata
def high_and_low(numbers)
numbers.split.map(&:to_i).minmax.reverse.join(' ')
end
Test.assert_equals(high_and_low("4 5 29 54 4 0 -214 542 -64 1 -3 6 -6"), "542 -214")
#Test Passed: Value == "542 -214"
Some docs about methods:
String#split Array#map Array#minmax Array#reverse Array#join
More about Symbol#to_proc
numbers.split.map(&:to_i) is same as number.split.map { |p| p.to_i }
But "minmax_by(&:to_i)" looks better, for sure I guess.

I keep getting an error that I don't understand

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>'
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 }
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.

increment a counter starting from 000

Typically when you want to have a counter, you can do something like this:
["a","b","c"].each.with_index(0) do |_case, i|
puts i
end
=> 0
=> 1
=> 2
We increment from 0. 0 is represented as a Fixnum in Ruby.
000 is also represented as a Fixnum in Ruby. But I need to increment as 000,001,002,003,etc. But instead it increments from 000 to 1:
["a","b","c"].each.with_index(000) do |_case, i|
puts i
end
=> 0
=> 1
=> 2
How get I increment 000 as 001,002,003,etc?
You can use the formatted printing functions printf and sprintf:
["a","b","c"].each_with_index { |_case, i| printf("%03d\n", i) }
000
001
002
If the goal is to print padded numbers then Ruby can do this for you by using string ranges. A few ways to do this:
puts ('001'..'005').to_a
or
('001'..'005').each { |n| puts n }
or
puts ('001'..'999').take(5)
All of which print:
#001
#002
#003
#004
#005

Ruby Array - highest integer

brand new to Ruby, and love it. Just playing around with the below code:
public
def highest
highest_number = 0
each do |number|
number = number.to_i
highest_number = number if number > highest_number
puts highest_number
end
end
array = %w{1 2 4 5 3 8 22 929 1000 2}
array.highest
So at the moment the response I get is:
1
2
4
5
5
8
22
929
1000
1000
So it puts the array first, then the highest number from the array as well. However all I want it to is put the highest number only...
I have played around with this and can't figure it out! Sorry for such a newbie question
The problem is that you have the puts statement inside the each loop, so during every iteration it prints out what the highest number currently is. Try moving it outside the each loop so that you have this:
public
def highest
highest_number = 0
each do |number|
number = number.to_i
highest_number = number if number > highest_number
end
puts highest_number
end
array = %w{1 2 4 5 3 8 22 929 1000 2}
array.highest
Which produces the desired output:
1000
You could also save yourself some trouble by using max_by:
>> a = %w{1 2 4 5 3 8 22 929 1000 2}
=> ["1", "2", "4", "5", "3", "8", "22", "929", "1000", "2"]
>> m = a.max_by { |e| e.to_i }
=> "1000"
You could also use another version of max_by:
m = a.max_by(&:to_i)
to avoid the extra noise of the "block that just calls a method".
But this is probably a Ruby blocks learning exercise for you so using existing parts of the standard libraries doesn't count. OTOH, it is good to know what's in the standard libraries so punting to max_by or max would also count as a learning exercise.
You can do this instead and avoid the highest_number variable.
array = %w{1 2 4 5 3 8 22 929 1000 2}
class Array
def highest
collect { |x| x.to_i }. \
sort. \
last.to_i
end
end
array.highest # 1000
The collect { |x| x.to_i } can also be written as collect(&:to_i) in this case.

Resources