Ruby - Accessing an Array from Inside a Function - ruby

Ruby Newb here. I'm trying to write a program that accepts user input, compares it with numbers in an array, and if there's a match, adds it to another number passed to the function. Like so:
numbers = [1, 2, 3, 4, 5]
def add(start_num, list)
print "What number will you add?> "
number = gets.chomp
if list.index(number) != nil
start_num = start_num.to_i
number = number.to_i
sum = start_num + number
puts "Your sum is #{sum}."
else
puts "Not an acceptable number."
end
end
add(10, numbers)
Every time it gets to the point where it compares list.index(number) to nil, it apparently doesn't pass, and spits out "Not an acceptable answer." So, for some reason, even if the user-input number matches a number from the numbers array, apparently the index is still equal to nil.
Anybody have a clue how I can make the test pass?

Just convert the string to number as
number = gets.chomp.to_i
In your code, you were searching inside the list the number, which is basically string. That's the reason your if condition always evaluated as falsy. BTW,
number = gets.to_i
Will work too.

get.chomp is a string I think try to transform it in a number with gets.chomp.to_i

From one newb to another (I know it can be hard, lol), here are some suggestions to clean up you code a little (I'm sure there are even cleaner versions but here's a start)
numbers = [1, 2, 3, 4, 5]
def add(start_num, list)
print "What number will you add?> " #using puts will give the user a new line
number = gets.chomp #to_i is best placed here, gets.chomp ALWAYS returns a string
if list.index(number) != nil #include? is cleaner and more readable
start_num = start_num.to_i #an integer defined in an argument stays an integer, therefor no need for this line
number = number.to_i #no need for this line if you define it above
sum = start_num + number
puts "Your sum is #{sum}."
else
puts "Not an acceptable number."
end
end
add(10, numbers)
In fact, you can use a terany to shorten your if statement...so here is your code, the cleaner version:
numbers = [1, 2, 3, 4, 5]
def add(start_num, list)
puts "What number will you add?"
number = gets.chomp.to_i
sum = start_num + number
list.include?(number) ? puts("Your sum is #{sum}.") : puts("Not an acceptable number.")
end
add(10, numbers)
less code is more;)

Related

Code won't function properly without the Integer method for Ruby to properly identify whether my input is either greater or less than when compared

I am brand new to programming. I am going through the Learn Ruby course on Codecademy. It's taking me through a exercise on experimenting with else/if statements. I'm attempting to run code where you input two integers (n and y) and print a statement based on whether n > y, n < y, or n == y.
As an example, when I input n = 5 and y = 15, it would print out the statement "I'm getting printed because n is greater than y) despite that not being true. Some set of numbers would print the correct statement, some set of numbers (as the one above) always printed the incorrect statement. After about 30 minutes of trying to figure out why it wouldn't work, I attempted adding the Integer method to my code and it works as intended. I'm just trying to understand why it wouldn't work properly prior to that.
Here is my code before:
print "Enter an integer for x:"
n = gets.chomp
print "Enter an integer for y:"
y = gets.chomp
if n < y
print "I'm getting printed because #{n} is less than #{y}"
elsif n > y
print "I'm getting printed because #{n} is greater than #{y}"
else
print "I'm getting printed because #{n} is equal to #{y}"
end
Here is my code after adding the Integer method:
print "Enter an integer for n:"
n = Integer(gets.chomp)
print "Enter an integer for y:"
y = Integer(gets.chomp)
if n < y
print "I'm getting printed because #{n} is less than #{y}"
elsif n > y
print "I'm getting printed because #{n} is greater than #{y}"
else
print "I'm getting printed because #{n} is equal to #{y}"
end
After going back in the lessons, I noticed an example Codecademy provided where they use the Integer method, but they do not go into detail about it. Regardless, I still added it to my code in the same fashion they used it in their example, and now it works properly. Like I said above, I just want to understand why it wouldn't work before and where it was going wrong in my code before I go any further in my lessons.
gets returns the string entered by the user, including the newline character created by pressing enter. gets.chomp removes the newline character at the end of the string, but still leaves the input a string.
And strings are sorted and compared alphabetically. "aa" < "b" correct when comparing strings and in the same sense "11" < "2" is correct for strings containing numbers.
But Integer(gets.chomp) translates the user input from a string containing a number into an integer (an actual number). And therefore the comparison works as expected afterward.
Documentation of the methods in play:
Kernel#gets
String#chomp
Kernel#Integer

Stack level too deep in recursion for largest palindrome product question (Project Euler)

I'm trying to implement a recursive solution to the largest palindrome product problem
What I'm trying to do is start both numbers at 999 and iterate down to 100 for num1 and then restart num1 at 999 and iterate num2 down by 1.
The goal is basically to mimic a nested for-loop.
def largest_palindrome_prod(num1 = 999, num2 = 999, largest_so_far = 0)
prod = num1 * num2
largest_so_far = prod if prod > largest_so_far && check_pal(prod)
if num2 == 100
return largest_so_far
elsif num1 == 100
largest_palindrome_prod(num1 = 999, num2 -= 1, largest_so_far)
else
largest_palindrome_prod(num1 -= 1, num2, largest_so_far)
end
end
#I know this function works, just here for reference
def check_pal(num)
num = num.to_s if num.is_a? Integer
if num.length < 2
true
else
num[0] == num[-1] ? check_pal(num[1..-2]) : false
end
end
rb:10:inlargest_palindrome_prod': stack level too deep`
I'm getting this error which is referring to the else statement in the largest_palindrome_prod function, but I can't figure out wast could be causing the stack error.
You don't have an infinite recursion bug. The stack is just running out of space because of the size of your input. To prove this, you can run your same function with the range of 2-digit numbers, instead of the 3-digit ones. It returns fine, which shows that there is no flaw with your logic.
How to get around this? Two options.
Option 1: You could simply not use recursion here (just use a regular nested loop instead)
Option 2: Keep your same code and enable tail call optimization:
# run_code.rb
RubyVM::InstructionSequence.compile_option = {
tailcall_optimization: true,
trace_instruction: false
}
require './palindrome_functions.rb'
puts largest_palindrome_prod
# => 906609
Note, for a reason I don't fully understand, the tail call optimization must be enabled in a different file than the code being run. So if you simply moved the compile_option line to the palindrome_functions.rb file, it wouldn't work.
I cant really give you a full explanation of tail call optimization (look it up on Wikipedia) but from my understanding, its a heavy optimization for recursive functions that only works when the recursive call is at the end of the function body. Your function meets this criteria.
#maxpleaner has answered your question and has shown how you can use recursion that avoids the stack level error. He also mentioned the option (which I expect he favours) of simply looping, rather than employing recursion. Below is one looping solution. The following method is used in the search1.
def check_ranges(range1, range2 = range1)
range1.flat_map do |n|
[n].product((range2.first..[n, range2.last].min).to_a)
end.map { |x,y| x*y }.
sort.
reverse_each.
find do |z|
arr = z.digits
arr == arr.reverse
end
end
Let's first find the largest palindrome of the product of two numbers between 960 and 999 (if there are any):
check_ranges(960..999)
#=> nil
There are none. Note that this calculation was very cheap, requiring the examination of only 40*40/2 #=> 800 products. Next, find the largest palindrome that is equal to the product of two numbers between 920 and 999.
check_ranges(920..999)
#=> 888888
Success! Note that this method re-checks the 800 products we checked earlier. It makes more sense to examine only the cases represented by the following two calls to brute_force:
check_ranges(960..999, 920..959)
#=> 888888
check_ranges(920..959)
#=> 861168
The first call computes 40*40 #=> 1600 products; the second, 800 products.
Of course, we have not yet necessarily found the largest product that is a palindrome. We do, however, have a lower bound on the largest product, which we can use to advantage. Since
888888/999
#=> 889
we infer that if the product of two numbers is larger than 888888, both of those numbers must be at least 889. We therefore need only check:
check_ranges(889..999, 889..919)
#=> 906609
check_ranges(889..919)
#=> 824428
We are finished. This tells us that 906609 is the largest product of two 3-digit numbers that is a palindrome.
The question does not ask what are the two numbers whose product is the largest palindrome, but we can easily find them:
(889..999).to_a.product((889..919).to_a).find { |x,y| x*y == 906609 }
#=> [993, 913]
993*913
#=> 906609
Moreover, let:
a = (889..999).to_a.product((889..919).to_a).map { |x,y| x*y }.
sort.
reverse
Then:
a.index { |n| n == 906609 }
#=> 84
tells us that only the largest 84 elements of this sorted group of 111*31 #=> 3441 products had to be examined before a palindrome (906609) was found.
All of this needs to be organized into a method. Though challenging for a newbie, it should be a good learning experience.
1. It would be useful to test which is faster, arr = z.digits; arr == arr.reverse or s = z.to_s; s == s.reverse.
#maxpleaner already answered, #Cary Swoveland already showed one brute force way using ranges and product. I'd like to show another brute force using a nested loop, easier to follow (IMO):
n = 9999
res = [0]
bottom = 10**(n.digits.size - 1)
n.downto(bottom) do |k|
k.downto(bottom) do |j|
# puts "#{k}, #{j}"
res = [k, j, k * j] if check_pal(k * j) && k * j > res.last
end
end
res
#=> [9999, 9901, 99000099]
I guess it can be optimized further, for example, using
n.downto(n*99/100) do |k|
k.downto(k*99/100) do |j|
Returned [99979, 99681, 9966006699] in 0.7 seconds.
Not required, but this increases the speed:
def check_pal(num)
word = num.to_s
word.reverse == word
end

Sort Integer Array Ruby

Have the function PermutationStep (num) take the num parameter being passed and return the next number greater than num using the same digits. For example: if num is 123 return 132, if it's 12453 return 12534. If a number has no greater permutations, return -1 (ie. 999)
Here's my code. I'd like to sort an array of large integers in numerical order. Using the regular sort method doesn't give the right order for some numbers. Is there a sort_by structure that I can replace 'sort' with in my code below?
def PermutationStep(num)
num = num.to_s.split('').map {|i| i.to_i}
permutations = num.permutation.to_a.sort #<= I want to sort by numerical value here
permutations.each_with_index do |n, idx|
if n == num
if n == permutations[-1]
return -1
else
return permutations[idx+1].join.to_i
end
end
end
end
For example, 11121. When I run the code it gives me 11121.I want the next highest permutation, which should be 12111.
Also, when I try { |a,b| b <=> a }, I also get errors.
You can pass a block to sort.
num.permutation.to_a.sort { |x, y| x.to_i <=> y.to_i }
This SO thread may be of some assistance: How does Array#sort work when a block is passed?
num.permutation.to_a is an array of arrays, not an array of integers, which causes the result not what you expected.
Actually you don't need to sort since you only need the minimum integer that is bigger than the input.
def PermutationStep(num)
nums = num.to_s.split('')
permutations = nums.permutation.map{|a| a.join.to_i}
permutations.keep_if{|n| n > num}.min || -1
end
puts PermutationStep(11121) # 11211
puts PermutationStep(999) # -1
Call to_i before your sort the permutations. Once that is done, sort the array an pick the first element greater than your number:
def PermutationStep(num)
numbers = num.to_s.split('')
permutations = numbers.permutation.map { |p| p.join.to_i }.sort
permutations.detect { |p| p > num } || -1
end
You don't need to consider permutations of digits to obtain the next higher number.
Consider the number 126531.
Going from right to left, we look for the first decrease in the digits. That would be 2 < 6. Clearly we cannot obtain a higher number by permuting only the digits after the 2, but we can obtain a higher number merely by swapping 2 and 6. This will not be the next higher number, however.
We therefore look for the smallest digit to the right of 2 that is greater than 2, which would be 3. Clearly, the next higher number will begin 13 and will have the remaining digits ordered smallest to largest. Therefore, the next higher number will be 131256.
You can easily see that the next higher number for 123 is 132, and for 12453 is 12534.
The proof that procedure is correct is easily established by induction, first showing that it is correct for numbers with two digits, then assuming it is correct for numbers with n>=2 digits, showing it is correct for numbers with n+1 digits.
It can be easily implemented in code:
def next_highest(n)
a = n.to_s.reverse.split('').map(&:to_i)
last = -Float::INFINITY
x,ndx = a.each_with_index.find { |d,i| res = d<last; last=d; res }
return nil unless x
swap_val = a[ndx]
swap_ndx = (0...ndx).select { |i| a[i] > swap_val }.min_by{ |i| a[i] }
a[ndx], a[swap_ndx] = a[swap_ndx], swap_val
a[0...ndx] = a[0...ndx].sort.reverse
a.join.reverse
end
next_highest(126531) #=> "131256"
next_highest(109876543210) #=> "110023456789"

ruby won't print output

I'm trying to see if the user enters a prime number. I want it to print "PRIME" or "NOT PRIME" to screen:
prime = ""
puts "TYPE IN A NUMBER TO SEE IF IT'S PRIME: "
gets.chomp(prime).to_i
for divide_by in 2..(prime.to_i - 1)
if prime % divide_by == 0
puts "NOT PRIME!!!"
else
puts "PRIME!!!"
end
end
Should I use a while loop instead?
Your gets.chomp(prime).to_i is not doing anything significant. I don't understand the purpose of chomp here, and it is not assigning any variable. If you want to receive the input number as prime, you need to do prime = gets.to_i.
Once you do that, you do not need to do to_i again as in for divide_by in 2..(prime.to_i - 1).
Furthermore, your logic is flawed. If prime is not divisible by 2, is that enough to say "PRIME!!"? I don't think so.
And if you are wondering what type of loop to use, the for loop is rarely useful. You should use each.

Finding palindromic numbers in Ruby

So, I'm doing Project Euler to solidify my Ruby skills. I'm on problem #4, which reads:
A palindromic number reads the same
both ways. The largest palindrome made
from the product of two 2-digit
numbers is 9009 = 91 * 99.
Find the largest palindrome made from
the product of two 3-digit numbers.
First, I'm trying to verify my code using the information from the first paragraph. I've defined a palindrome function as so:
def palindrome?(blah)
string = blah.to_s
string.reverse == string
end
My code looks like:
array = (90..99).to_a
array = array.map{|u| array.map{|y| u*y}}
array = array.sort
array = array.select{|u| palindrome?(u)}
puts array
The program doesn't output anything. If I do the following:
array = (90..99).to_a
array = array.map{|u| array.map{|y| u*y}}
array = array.sort
#array = array.select{|u| palindrome?(u)}
puts array
I get a long series of unsorted four-digit numbers, so I guess it's ignoring the sort. Finally, if I simply do:
#array = (90..99).to_a
#array = array.map{|u| array.map{|y| u*y}}
#array = array.sort
array = [7447, 9009, 3551, 2419]
array = array.select{|u| palindrome?(u)}
puts array
I get 7447 and 9009, like I should. Why is this happening?
I'm using 1.8.6, because that's the only version available on this Windows machine.
This line of yours
array = array.map{|u| array.map{|y| u*y}}
returns a nested array, you should unwrap.
Hints: (but I'm not going to tell you how)
You probably don't need sort on the intermediary value
You need to remove duplicates
Tips:
next time, run your code in the interactive interpreter, that way you'll see the result of each line of code.
You can use something like this
new_arr = array.inject([]) { |a,u| a += array.map { |y| u*y } }
instead of
array = array.map{|u| array.map{|y| u*y}}
it returns a nested "[ [8100,..],[],[] ] " type of array. So thats the reason why your code doesn't work
This looks more understandable:-
#Steps
# Define a method for palindrome
# List out all 3-digit numbers
# Multiply each numbers by each numbers
# List out all palindrome numbers
# Choose the largest (max) palindrome number
def is_a_palindrome?(n)
n == n.to_s.reverse.to_i
end
def problem_four
palindrome = [ ]
array = 111.upto(999)
array.each do |x|
array.each do |y|
multiply = x * y
if is_a_palindrome?(multiply)
palindrome << multiply
end
end
end
palindrome.max
end
puts problem_four
#$ ruby problem_four.rb
#906609
Find the largest palindrome made from the product of two 3-digit numbers.
I have made this solution, I hope this will help some newbie
to=999
from=100
palindromes=[]
for i in from..to do
for j in 1..to do
k=i*j
palindromes << k if k.to_s==k.to_s.reverse
end
end
palindromes.max #this will return 906609

Resources