Ruby: Take input and take it as loop range - ruby

a = $stdin.read
for i in 0..(a)
puts "Hi"
end
This is giving syntax error-in `
': bad value for range (ArgumentError). What should be improved to get output for a=3 as
Hi
Hi
Hi

The error is because a is a string, you can make it an integer by:
a = a.to_i

You have to convert the string to an integer (.to_i).
Note: prefer to use times:
a.to_i.times { puts "Hi" }

You need an integer to be used, or you get the ArgumentError. This will accept your input and ensure that it can be converted to an Integer. You can read about the Kernel#Integer method for specifics.
a = Integer($stdin.read)
for i in 0..(a)
puts "Hi"
end

Related

Write a program which gets a number from a user and identify whether it is an Integer or a Float in ruby

I am trying this :
print " Enter Value "
num = gets.chomp
also tried .kind_of? but didn't work
if num.is_a? Float
print " Number is in float "
also tried .kind_of? but didn't work
else num.is_a? Integer
print " Number is in integer "
end
Your problem here is that gets returns a String you can actually determine this based on the fact that you are chaining String#chomp, which removes the trailing "separator" which by default is return characters (newlines) e.g.
num = gets.chomp # User enters 1
#=> "1"
In order to turn this String into a Numeric you could explicitly cast it via to_i or to_f however you are trying to determine which one it is.
Given this requirement I would recommend the usage of Kernel#Integer and Kernel#Float as these methods are strict about how they handle this conversion. knowing this we can change your code to
print " Enter Value "
num = gets.chomp
if Integer(num, exception: false)
puts "#{num} is an Integer"
elsif Float(num, exception: false)
puts "#{num} is a Float"
else
puts "#{num} is neither an Integer or a Float"
end
Note: the use of exception: false causes these methods to return nil if the String cannot be converted to the desired object, without it both methods will raise an ArgumentError. Additionally when I say these methods are strict about conversion a simple example would be Integer("1.0") #=> ArgumentError because while 1 == 1.0, 1.0 itself is a Float and thus not an Integer
Some examples:
num = 6.6
num.is_a?(Integer)
=> false
num.is_a?(Float)
=> true
num = 6
num.is_a?(Integer)
=> true
num.is_a?(Float)
=> false
Minor note, #print is not the correct method to print to the screen. The correct method is #puts.
So your code would look like this:
if num.is_a?(Float)
puts 'Number is a float.'
elsif num.is_a?(Integer)
puts 'Number is an integer.'
else
puts 'Number is neither a float nor an integer.'
end
I suspect #gets returns a string though, which means you'll need to convert from a string into a numeric first.

ruby code with the NoMethodError

When running the following Ruby code:
#!/usr/bin/env ruby
ar=[]
class String
def to_int
self == self.to_i
end
end
ARGV.each do |a|
ar.push("#{a}")
end
ar.map(&:to_int).sort
ar.each do |x|
print x + " "
end
puts ""
I am getting the following error:
example.rb:14:in `sort': undefined method `<=>' for false:FalseClass (NoMethodError)
This program needs to be running with the command line argument with a list of numbers. Any help will be appreciated.
ARGV.sort.each { |x| print x + " " }
puts
class String
def to_int
self == self.to_i
end
end
This to_int method will return either a true or false. So when you run this line: ar.map(&:to_int).sort, the map method will map the entire array into true or false.
You array will look like [false,false,true,false], which will fail when you run the sort function.
I'm not sure what the purpose of the to_int function is, you just need to map with the simple to_i function, then sort it.
ar.map!(&:to_i).sort
Make sure you use the map! so your original array is modified.
If you do map the array into integers, you will have to modify the print line to
ar.each do |x|
print x.to_s + " "
end
Otherwise you will get an error:
String can't be coerced into Fixnum
When I run this using Ruby 2.3.0, I don't get that error.
I tried Ruby 2.0.0p648 (which comes with OS X), 2.1.5, and 2.2.4, and they don't raise that error either.
It's a bit unclear to me what you're trying to accomplish here.
You're doing things that don't make any sense, but I'll assume you're trying to learn Ruby and you're just trying different things.
#!/usr/bin/env ruby
ar=[]
# This is "monkey patching" String, and is a bad practice.
class String
# A method named "to_int" implies a conversion to integer. But the "to_i" method already does
# that, and this method doesn't convert to an integer, it converts to a boolean.
def to_int
# Comparing the string to itself as an integer. Why would it ever be true?
self == self.to_i
end
end
# I'm assuming that this is intended to convert the argument list to a list of strings.
# But ARGV should already a list of strings.
# And this would be better done as `ar = ARGV.map(&:to_s)`
ARGV.each do |a|
ar.push("#{a}");
end
# This creates an array of values returned by `to_int`, then sorts the array.
# Since `String#to_int` (defined above) returns booleans, it's an array of "false" values, so
# sorting does nothing. But then the value of the `sort` is ignored, since it's not assigned to
# a variable. If you want to modify the order of an existing array, use `sort!`.
# But if you're trying to sort the array `ar` by the numeric values, `ar.sort_by(&:to_i)` would
# do that.
ar.map(&:to_int).sort
ar.each do |x| print x + " "; end
puts ""
It seems like you're trying to print the arguments in their numeric order.
This can be accomplished with
puts ARGV.sort_by(&:to_i).join(" ")

Trying to convert a number to binary form

I wrote a simple program which works:
a = 4.to_s(2)
puts a.reverse
I want to be able to change it based on input from the user in the terminal. This is what I wrote:
puts 'Please enter a number you would like to see expressed in binary form'
i = gets.chomp
b = i.to_s(2)
puts b
This is the error that I keep getting:
`to_s': wrong number of arguments(1 for 0) (ArgumentError)
You're starting with a string, so you need to convert it:
i.to_i.to_s(2)
The #to_s method on a string doesn't take any arguments.
You do not need the chomp method, #to_i will take care of it.
Write it as:
puts 'Please enter a number you would like to see expressed in binary form'
i = gets.to_i
b = i.to_s(2)
puts b
You are calling to_s on an string, not on integer as you are thinking, because Kernel#gets always gives you a String object.
First, convert it to Fixnum, then call Fixnum#to_s on the Fixnum instance, which takes an argument, but String#to_s doesn't accept arguments, which was why you got a complaint from Ruby.
It seems that you want to use Fixnum#to_s but in your program gets.chomp returns a string, so you actually call String#to_s
You can could do:
i = gets.chomp.to_i

elegant way to check if a string inputed by user is an integer in ruby?

I'm trying to validate that the input a user gives my program via gets is an integer. is_a?(Integer) does not work, as far as i can tell, because gets gets a string from the user, so it will always return false even if the user enters an valid integer (in string form). One would think I could simply use to_i on the input and be done with it, but that raises another issue - "75akjfas".to_i results in 75. So if I relied on to_i to solve my problems, anything starting with numbers will work.
How do I cleanly validate that the value is an integer only, and not a combination of numbers and letters? Or do I need to resort to regex for this?
print "Enter an integer (or try to sneak by something other): "
puts Integer(gets) rescue puts "Hey, that's not an integer!"
How about s.to_i.to_s == s? I'd prefer regex however.
Using regex you could do it like this:
class String
def integer?
!!(self =~ /^[-+]?[0-9]+$/)
end
end
You could use Integer() but you need to be careful with hex, binary, or octal input. http://ruby-doc.org/core-2.3.1/Kernel.html#method-i-Integer
def valid_integer?(string)
begin
!!Integer(string)
rescue ArgumentError
false
end
end
Check this code example for how to use the checked string input by the user
puts "Enter a number: "
user_input = gets.chomp
check = (user_input.to_i.to_s == user_input)
while (!check ) do
puts("Wrong Input, Pls, Enter a number: " )
user_input = gets.chomp
check = (user_input.to_i.to_s == user_input)
end
if user_input.to_i < 0
puts "Number is negative"
elsif user_input.to_i > 0
puts "Number is positve"
else
puts "Number is Zero"
end
Ruby can do it without esoteric solutions:
Integer is a integer
1970.is_a?Integer
true
String is not a integer
"1970".is_a?Integer
false
String to integer is a integer
"1970".to_i.is_a?Integer
true

Safe integer parsing in Ruby

I have a string, say '123', and I want to convert it to the integer 123.
I know you can simply do some_string.to_i, but that converts 'lolipops' to 0, which is not the effect I have in mind. I want it to blow up in my face when I try to convert something invalid, with a nice and painful Exception. Otherwise, I can't distinguish between a valid 0 and something that just isn't a number at all.
EDIT: I was looking for the standard way of doing it, without regex trickery.
Ruby has this functionality built in:
Integer('1001') # => 1001
Integer('1001 nights')
# ArgumentError: invalid value for Integer: "1001 nights"
As noted in answer by Joseph Pecoraro, you might want to watch for strings that are valid non-decimal numbers, such as those starting with 0x for hex and 0b for binary, and potentially more tricky numbers starting with zero that will be parsed as octal.
Ruby 1.9.2 added optional second argument for radix so above issue can be avoided:
Integer('23') # => 23
Integer('0x23') # => 35
Integer('023') # => 19
Integer('0x23', 10)
# => #<ArgumentError: invalid value for Integer: "0x23">
Integer('023', 10) # => 23
This might work:
i.to_i if i.match(/^\d+$/)
Also be aware of the affects that the current accepted solution may have on parsing hex, octal, and binary numbers:
>> Integer('0x15')
# => 21
>> Integer('0b10')
# => 2
>> Integer('077')
# => 63
In Ruby numbers that start with 0x or 0X are hex, 0b or 0B are binary, and just 0 are octal. If this is not the desired behavior you may want to combine that with some of the other solutions that check if the string matches a pattern first. Like the /\d+/ regular expressions, etc.
Another unexpected behavior with the accepted solution (with 1.8, 1.9 is ok):
>> Integer(:foobar)
=> 26017
>> Integer(:yikes)
=> 26025
so if you're not sure what is being passed in, make sure you add a .to_s.
I like Myron's answer but it suffers from the Ruby disease of "I no longer use Java/C# so I'm never going to use inheritance again". Opening any class can be fraught with danger and should be used sparingly, especially when it's part of Ruby's core library. I'm not saying don't ever use it, but it's usually easy to avoid and that there are better options available, e.g.
class IntegerInString < String
def initialize( s )
fail ArgumentError, "The string '#{s}' is not an integer in a string, it's just a string." unless s =~ /^\-?[0-9]+$/
super
end
end
Then when you wish to use a string that could be a number it's clear what you're doing and you don't clobber any core class, e.g.
n = IntegerInString.new "2"
n.to_i
# => 2
IntegerInString.new "blob"
ArgumentError: The string 'blob' is not an integer in a string, it's just a string.
You can add all sorts of other checks in the initialize, like checking for binary numbers etc. The main thing though, is that Ruby is for people and being for people means clarity. Naming an object via its variable name and its class name makes things much clearer.
I had to deal with this in my last project, and my implementation was similar, but a bit different:
class NotAnIntError < StandardError
end
class String
def is_int?
self =~ /^-?[0-9]+$/
end
def safe_to_i
return self.to_i if is_int?
raise NotAnIntError, "The string '#{self}' is not a valid integer.", caller
end
end
class Integer
def safe_to_i
return self
end
end
class StringExtensions < Test::Unit::TestCase
def test_is_int
assert "98234".is_int?
assert "-2342".is_int?
assert "02342".is_int?
assert !"+342".is_int?
assert !"3-42".is_int?
assert !"342.234".is_int?
assert !"a342".is_int?
assert !"342a".is_int?
end
def test_safe_to_i
assert 234234 == 234234.safe_to_i
assert 237 == "237".safe_to_i
begin
"a word".safe_to_i
fail 'safe_to_i did not raise the expected error.'
rescue NotAnIntError
# this is what we expect..
end
end
end
someString = "asdfasd123"
number = someString.to_i
if someString != number.to_s
puts "oops, this isn't a number"
end
Probably not the cleanest way to do it, but should work.
Re: Chris's answer
Your implementation let's things like "1a" or "b2" through. How about this instead:
def safeParse2(strToParse)
if strToParse =~ /\A\d+\Z/
strToParse.to_i
else
raise Exception
end
end
["100", "1a", "b2", "t"].each do |number|
begin
puts safeParse2(number)
rescue Exception
puts "#{number} is invalid"
end
end
This outputs:
100
1a is invalid
b2 is invalid
t is invalid

Resources