Can't change Strings into int in `[]` - ruby

In ruby, I try to convert a String to Int in operator '[]' But failed.
Here is the code (my input is 14 45):
STDIN.gets.split(/\s+/).each do |str|
book = tags[str.to_i] # book is just a new variable. tags is an array
end
the ruby will stop with an error:
in '[]': no implicit conversion of String into Integer (TypeError)
So I change my code to follows(this one works well.):
STDIN.gets.split(/\s+/).each do |str|
number = str.to_i # for converting
book = tags[number]
end
This one works well. But I must add one more line for converting. Is there a good way for avoiding that line?
my version of ruby is: $: ruby --version ==> ruby 2.0.0p0 (2013-02-24 revision39474) [i686-linux]
Hi Guys, Please let me KNOW why you still want to close this topic. THANKS.

The error message you are getting will definitely only ever occur when you pass a String as an index to Array#[]. So you are probably not showing us the source that you are actually running. Consider:
a = [1,2,3]
str = 'string'
str.to_i
#=> 0
a[str.to_i]
#=> 1
number = str.to_i
#=> 0
a[number]
#=> 1
a['string']
# TypeError: no implicit conversion of String into Integer
By the way, the error message in your question is specific to Ruby 2.0.0:
RUBY_VERSION
#=> "2.0.0"
a = [1,2,3]
a['string']
# TypeError: no implicit conversion of String into Integer
Whereas in Ruby 1.9.3-p392 you will get this error message:
RUBY_VERSION
#=> "1.9.3"
a = [1,2,3]
a['string']
# TypeError: can't convert String into Integer

Related

Ruby not allowing me to compare values

I made the code below, but when I run it, including if I pick the correct number, the console prints the debug. Why is this? What am I doing wrong?
puts 'Welcome to the number guessing game. I will pick a number between 1-100. It will be your job to guess the number. If you are incorrect, I will tell you if your guess is higher or lower than my number, I will let you know.'
puts "Time to guess!"
mine = (rand(1..100))
puts mine
grabber = gets.chomp!
if mine == grabber
puts 'That\'s it!'
else
print 'debug'
end
You're comparing values of two different types. gets returns a string, rand(1..100) returns an integer. You can't compare them directly. You need to convert them to the same type, either both integer or both string.
Try using to_i on the string to convert it to an integer:
if mine == grabber.to_i
As #meagar said, you are comparing different types (a string from gets and a number from rand) which will always returning false.
That being said, you have a couple of different ways to coerce/convert datatypes in ruby.
The most common one, as #maeger showed, is using to_i, however it can lead to some strange behaviours as any string that isn't easily parsed as an integer will return 0.
2.5.3 :001 > 'potato'.to_i
=> 0
2.5.3 :002 > '0xff'.to_i
=> 0
If you want to avoid this you can use Integer(arg), this is actually a method defined in Kernel that will do its best to verify if the string is actually convertible into an integer and if it fails it will raise an ArgumentError.
2.5.3 :001 > Integer('potato')
=> ArgumentError (invalid value for Integer(): 'potato')
2.5.3 :002 > Integer('2')
=> 2
2.5.3 :003 > Integer('0xff') # Hexadecimal
=> 255
2.5.3 :004 > Integer('0666') # Octal
=> 438
2.5.3 :005 > Integer('0b1110') # Binary
=> 14

Expanding empty hash in variable with double splat in Ruby

I got this strange behavior trying to expand the hash variable using double splat. Do not know why this is happening.
My ruby version
ruby 2.2.6p396 (2016-11-15 revision 56800)
Scenario
class MyClass
def my_method; end
end
MyClass.new.my_method(*[]) # returns nil
MyClass.new.my_method(**{}) # returns nil
MyClass.new.my_method(*[], **{}) # returns nil
# Using variables
values = []
k_values = {}
MyClass.new.my_method(*values) # returns nil
MyClass.new.my_method(**k_values) # *** ArgumentError Exception: Wrong number of arguments. Expected 0, got 1.
MyClass.new.my_method(*values, **k_values) # *** ArgumentError Exception: Wrong number of arguments. Expected 0, got 1.
# In summary
MyClass.new.my_method(**{}) # returns nil
MyClass.new.my_method(**k_values) # *** ArgumentError Exception: Wrong number of arguments. Expected 0, got 1.
Does any one knows why this is happening? Is this a bug?
Yes, it very looks like a bug
def foo(*args)
args
end
foo(**{})
# => []
h = {}
foo(**h)
# => [{}]
It passes empty hash as first argument in case of double splat of variable.
My version is ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin16]

Accidental Type conversion in Ruby with strings

I'm trying to solve a challenge where you take in a string of words but return the longest word in the string. My strategy is to break the string into an array of individual words and search the array. However, I'm getting a type conversion error. What is causing the type conversion error? This is particularly strange to me because I don't actually see any type conversion happening here.
def LongestWord(sen)
sen1 = sen.split("/\W+/")
grt = 0
sen1.each do |i|
if sen1[i].length > sen1[grt].length # Type conversion error
grt = i
end
end
sen1[grt]
end
# keep this function call here
puts LongestWord(STDIN.gets)
The type conversion is caused by the array entry i being converted (probably unsuccessfully) into an integer (though I suppose it could be ruby trying to convert the array into a hash, and use i as a key to the hash).
Your misunderstanding is that you think you're getting the array's indices passed into the block for each. What is passed in to that block is each individual value in the array. I.e., if your string sen is 'this is a silly string', then the values passed are 'this', 'is', 'a', 'silly', and 'string'.
You get the error because, when the code is running, i is the first value of sen1, which results in sen1['some string'] being evaluated.
An array can't have a string index, only a hash can, resulting in the Type error.
Meditate on this:
def longest_word(sen)
sen1 = sen.split # => ["foo", "barbaz"]
grt = 0
sen1.each do |i|
i # => "foo"
sen1 # => ["foo", "barbaz"]
sen1[i] # =>
sen1[grt] # =>
sen1[i].length # =>
sen1[grt].length # =>
if sen1[i].length > sen1[grt].length #Type conversion error
grt = i # =>
end
end
sen1[grt]
end
# keep this function call here
longest_word('foo barbaz')
Breaking it down further, here's the offending problem:
sen1 = 'foo barbaz'.split
sen1['foo'] # =>
# ~> TypeError
# ~> no implicit conversion of String into Integer
You don't see the type conversion, but it is there. In more than one place.
As Derrell Durrett pointed out in his answer, your are assuming (wrongly) that the index of the array is passed to the block, not its elements.
Then you write if sen1[i].length > sen1[grt].length. Let's consider the string is 'this is a silly string'. The first element is 'this' and what you are trying to do is if sen1['this'].length > sen1[0].length. As Ruby arrays always have integer indexes, Ruby tries to convert 'this' to an integer in order to find the element at the specified position. Of course this fails!
But your code is not that far from being right. A few small changes and it will run perfectly well:
def longest_word(sen)
sen1 = sen.split(" ")
grt = 0
sen1.each_index do |i|
if sen1[i].length > sen1[grt].length
grt = i
end
end
sen1[grt]
end
puts LongestWord(STDIN.gets)
Now you'd be passing the indexes with sen1.each_index and it'd be working fine.
Notice that I changed the name of your method to longest_word. This is much better, in fact, because this first capital letter is reserved to constants and class names.
I also would like to point that you are not using a good Ruby style. This could be written like this:
def longest_word(str)
str.split(" ").max_by{ |s| s.length }
end
and the result would be the same.

Ruby - cannot convert individual chars in string to ASCII

I am trying to run the following code on http://repl.it/languages/Ruby/, but I am encountering a NoMethodError:
a = "string"
a.each_char do |c|
puts c.ord
end
The error details are as follows:
(eval):1: undefined method `ord' for "s":String (NoMethodError)
from (eval):0:in `each_char'
from (eval):0
Please could somebody explain to me why my code does not work?
The each_char method of String yields each character as a separate String.
The Ruby version running on repl.it is quite old (1.8.7). The String class in that version of Ruby doesn't define an ord method, so your code fails to run with a NoMethodError.
ord was added to String in Ruby 1.9, so your code will run on newer versions of Ruby.
On Ruby 1.8.7 (and repl.it), you could use one of the following alternatives instead:
a = "string"
a.each_char do |c|
puts c[0]
end
a = "string"
a.each_byte do |c|
puts c
end
However, please note that these examples won't behave identically to your original code if your string uses a multi-byte encoding. The ord method returns a Unicode code point. The Ruby 1.8.7 examples will give you individual bytes.
The code as is will print the ascii code of each letter. Perhaps you're looking at the return value which would be the original string "string"?

Why do I get different results in IRB and a script?

Is there a difference in how IRB and Ruby execute some expressions?
These expressions give different results in IRB and when run from the command line. The question is, which one is correct?
IRB:
>> s = 'hello'
=> "hello"
>> s.size
>> s[s.length] = '!'
IndexError: index 5 out of string
from (irb):31:in `[]='
from (irb):31
>>
And in the normal script:
s = 'hello'
s[s.length] = '!'
puts s
laptop user$ ./prgruby.rb
hello!
Here is the doc of String#[] for 1.8.7 :
str[fixnum] = fixnum
The forms that take a Fixnum will raise an IndexError if the value is
out of range
Here is the same doc for 1.9.3 : the same definition is present
After test, what happen in Ruby 1.9.3 is s.length is not out of range for assignation. This make sense at it is the end of the string : you do not have to arbitrary fill the missing indexes but I guess it may be or should be documented somewhere ?

Resources