Whats wrong with the modulus operator in this Ruby code? - ruby

def factors_to_three (n)
puts n
if n % 3 == 0
puts "Your number is divisible by 3"
else
puts "Your Number is NOT divisible by 3"
end
end
puts "Enter the number to check if its divisible by 3"
number = gets.chomp
factors_to_three(number)
No matter what number I input, my program always outputs Your Number is NOT divisible by 3, even when clearly is.

n is not an integer. gets() returns a string and chomp removes the newline, but the data is still a string.
"6" % 3 != 0
6 % 3 == 0
You need to convert your incoming data to an integer representation.

Your result will always be false because gets.chomp returns a String:
number = gets.to_i
The above code will work but you must always type an integer. There are better ways to manage checking to see if the input is valid.
So you could check first like this:
number = gets
factors_to_three(number.to_i) if number.is_a?(Integer)

When text is read using gets, it is read in as a string. So in your code, number is actually not a number, but a string. Because of this, the "modulus" operator is in fact not the modulus operator, but the format operator on String, String#%:
Format—Uses str as a format specification, and returns the result of applying it to arg. If the
format specification contains more than one substitution, then arg
must be an Array or Hash containing the values to be substituted. See
Kernel::sprintf for details of the format string.
"%05d" % 123 #=> "00123"
"%-5s: %08x" % [ "ID", self.object_id ] #=> "ID : 200e14d6"
"foo = %{foo}" % { :foo => 'bar' } #=> "foo = bar"
As you can see, this method returns a string, which does not equal zero. Therefore, this program will always say that the number is not divisible by 3, even when it is.
You can fix this by calling to_i on the input returned from get:
number = gets.chomp.to_i

Related

Ruby four-digit number, how to check it whether they are two the same numbers

How to check that there are at least two the same values on four-digit number or there aren't at least two the same values
for example 2432 - there are two 2, how to check it and then spit out an information that there are at least two or more the same numbers in this four-digit number?
puts "enter four-digit number: "
four_digit_num = gets.chomp.to_i
You can do that as follows.
r = /(\d)\d*\1/
gets.match?(r) # when gets #=> "1231\n"
#=> true
gets.match?(r) # when gets #=> "1232\n"
#=> true
gets.match?(r) # when gets #=> "1234\n"
#=> false
We can write the regular expression in free-spacing mode to make it self-documenting.
r = /
(\d) # match a digit and save to capture group 1
\d* # match zero or more digits
\1 # match the contents of capture group 1
/x # specify free-spacing regex definition mode
See String#match?.
If you must begin with the integer
four_digit_num = gets.to_i
you could write
arr = four_digit_num.digits
arr.uniq.size < arr.size
or convert it to a string and apply the first method above:
four_digit_num.to_s.match?(r)
Test for unique digits:
four_digit_num = gets.to_i
digits = four_digit_num.digits # leading zeros will disappear
puts "2 or more same digits." if digits != digits.uniq
You can have up to two pairs of duplicates, so that's probably a use case that needs to be handled. In any case, with Ruby 2.7.2 you might use a Hash to count occurrences of each digit in your String using Hash#tally (via Enumerable) like so:
def report_duplicates_in(digits)
dupes = digits.to_s.chars.tally.select { _2 > 1 }
puts "dupliicate digits=>counts for #{digits}: #{dupes}" if dupes.any?
[digits, dupes]
end
# test with some values
%w[1234 2432 2442].map do |four_digit_num|
report_duplicates_in(four_digit_num)
end.to_h
This will print the following to standard output and return a Hash:
dupliicate digits=>counts for 2432: {"2"=>2}
dupliicate digits=>counts for 2442: {"2"=>2, "4"=>2}
#=> {"1234"=>{}, "2432"=>{"2"=>2}, "2442"=>{"2"=>2, "4"=>2}}

How do you get the output in Ruby to sort in even and odd numbers?

I got this assignment in Codecademy. I want to print the even numbers.
print "Print any number:"
inpt = gets.chomp
def odd_or_even(num)
if num % 2 == 0
print "even"
else
print "odd"
end
end
I do not get any output. Is the problem in the method, or how I've written the equation? I've tried changing both.
You defined the method odd_or_even but never actually call it.
You have two options:
Take the more script-like approach and work with the input without the use of methods:
print 'Print any number: '
input = gets.to_i
# ^ convert the input (which is always a string) to an integer
if input % 2 == 0
puts 'even'
# ^ is the same as `print` but adds a newline character at the end
# (unless the string ends with a newline character)
else
puts 'odd'
end
If you want to use a method you'll have to define it and call it as well:
def odd_or_even(num)
if num % 2 == 0
puts 'even'
else
puts 'odd'
end
end
print 'Print any number: '
input = gets.to_i
odd_or_even(input)
# ^ method is called here
Ruby also has a lot of build-in helpers. You can achieve the same result with the following two lines:
print 'Print any number: '
puts gets.to_i.odd? ? 'odd' : 'even'
references:
#gets get user input
String#to_i convert input to an integer
Integer#odd? check if the integer is odd
Ternary if: use inline of if expression ? true : false
I think you have to check your input data.
Otherwise it may be a situation:
'abc'.to_i.even? #=> true
It's because non-digital String#to_i returns 0.
As you see it's not good.
def odd_or_even(number)
number.odd? ? 'odd' : 'even'
end
puts 'Print any number:'
input = gets.chomp
if input =~ /\D/
puts 'It is not a number'
else
puts "It's #{odd_or_even(input.to_i)}"
end
Firstly we validate data using regex. If it's not a number we will not check is it odd or even.
Note:
Very often we use =~ operator to match String and Regexp.
/\D/ means any non-digit character.
i = 20
loop do
i -= 1
next if i % 2 == 1
print "#{i}"
break if i <= 0
end
I see two issues with what you've posted - first gets.chomp is going to return a string and you really want an integer, so you'd want to do gets.to_i (or Integer(gets) if you want to guard against non-numeric inputs). The second is that print doesn't include a line break, so that could be the source of your "no output" issue - maybe try switching to puts instead?

How do I check if user input is an integer in Ruby?

I am trying to loop until user inputs an integer. When user inputs a letter, the following code should print "Think of a number":
print "Think of a number "
while user_input = gets.to_i
if user_input.is_a? Integer
puts "your number is #{user_input}"
break
else
print "Think of a number "
end
end
I succeeded with my code when user inputs an integer. However when user inputs a string, the to_i method returns 0, and does not execute the else statement because it is a number.
The main issue with your code is String#to_i method is omnivorous.
"0".to_i #⇒ 0
"0.1".to_i #⇒ 0
"foo".to_i #⇒ 0
That said, user_input in your code is always integer.
What you probably want is to accept digits only (and maybe a leading minus for negatives.) The only concise way to accept a subset of characters is a regular expression.
# chomp to strip out trailing carriage return
user_input = gets.chomp
if user_input =~ /\A-?\d+\z/
...
The regular expression above means nothing save for digits with optional leading minus.
Or, even better (credits to #Stefan)
if gets =~ /\A-?\d+\Z/
If you only want to accept postive digits, you can use a range:
user_input = gets.chomp
if ('0'..'9').cover? user_input
let check below one used Integer(gets.chomp) rescue ''
print "Think of a number "
while user_input = Integer(gets.chomp) rescue ''
if user_input.is_a? Integer
puts "your number is #{user_input}"
break
else
print "Think of a number "
end
end
I came across a similar problem. I ended up doing this:
if user_input.strip == user_input.to_i.to_s
# More code here!
end
Testing for float would be:
if user_input.strip == user_input.to_f.to_s
# More code here!
end
Solved my issue. See if it helps.

Loop won't break and string won't capitalize properly?

I am trying to get a simple Ruby program to run correctly.
I need it to take user input until the user types q for "quit". It also needs to capitalize the last four letters of the users input and, with input under four letters, to capitalize all letters.
It only works for input over four letters, and, when I type "quit", it gets a nil error.
See the code below.
I am using Eclipse with Ruby 2.0.
puts ("\n" * 10)
loop do
puts "Please enter a word. (To quit type q.)" # Gets the users input
puts ("\n" * 3) #Scroll the screen 3 times
str = gets.chomp #Collect the player's response
puts ("\n" * 3) #Scroll the screen 3 times
length = str.length # Counts length of string
str = str[0..(length-5)] + str[(length-4)..length].upcase # Only makes last four letters of user input capitalized
puts str # Shows on screen the user input with capitalized last four letters
puts ("\n" * 3) #Scroll the screen 3 times
break if str == "q"
end
You need to pay attention to [] when you write code like this:
str = str[0..(length-5)] + str[(length-4)..length].upcase
If an index is negative, it is counted from the end of string. For example:
str = "abcde"
str[-1] # => "e"
str[-2] #=> "d"
See String.[] for more details.
With regard to your question, here is my logic:
break if str == "q"
if str.length < 4
str = str.upcase
else
str = str[0...-4] + str[-4..-1].upcase
end
p str
You need to do some checks on your length. If length is less than 4, than length - 5 will return a negative number and your
str[0..(length-5)] + ...
line will be upset. For example. If you type "str", then your code will try to do:
length = 3
str[0..-2] + str[-1..3]
which doesn't make sense. Also, since you check for str == "q" at the end, this is likely also happening for "q". Move your check and break up in the block, and make sure you don't treat all strings as if they're going to be longer than 4 characters.

What is the meaning of i.to_s in Ruby?

I want to understand a piece of code I found in Google:
i.to_s
In the above code i is an integer. As per my understanding i is being converted into a string. Is that true?
Better to say that this is an expression returning the string representation of the integer i. The integer itself doesn't change. #pedantic.
In irb
>> 54.to_s
=> "54"
>> 4598734598734597345937423647234.to_s
=> "4598734598734597345937423647234"
>> i = 7
=> 7
>> i.to_s
=> "7"
>> i
=> 7
As noted in the other answers, calling .to_s on an integer will return the string representation of that integer.
9.class #=> Fixnum
9.to_s #=> "9"
9.to_s.class #=> String
But you can also pass an argument to .to_s to change it from the default Base = 10 to anything from Base 2 to Base 36. Here is the documentation: Fixnum to_s. So, for example, if you wanted to convert the number 1024 to it's equivalent in binary (aka Base 2, which uses only "1" and "0" to represent any number), you could do:
1024.to_s(2) #=> "10000000000"
Converting to Base 36 can be useful when you want to generate random combinations of letters and numbers, since it counts using every number from 0 to 9 and then every letter from a to z. Base 36 explanation on Wikipedia. For example, the following code will give you a random string of letters and numbers of length 1 to 3 characters long (change the 3 to whatever maximum string length you want, which increases the possible combinations):
rand(36**3).to_s(36)
To better understand how the numbers are written in the different base systems, put this code into irb, changing out the 36 in the parenthesis for the base system you want to learn about. The resulting printout will count from 0 to 35 in which ever base system you chose
36.times {|i| puts i.to_s(36)}
That is correct. to_s converts any object to a string, in this case (probably) an integer, since the variable is called i.

Resources