I have Integers in an array that I need converted to strings - ruby

When I type
digicollect=[]
digicollect[0]=2
I get 2 when I type in digicollect in the irb.
Also, when I type in
"Hello" * 2
I get "HelloHello"
But if I type in
2 * "Hello"
it doesn't work.
"hello" * digicollect
doesn't work.
but
"hello" * digicollect[0]
does work.
Why?

Everything in ruby is an object, and even multiplications are just method calls.
"Hello" * 2 is the same as "Hello".*(2)
So when you get an error you should ask yourself: Do the left hand side really have the multiplication method and will it accept the right hand side as an argument?
digicollect = []
digicollect[0] = 2
Let us check what kind of objects we have:
p digicollect.class #=> Array
p digicollect[0].class #=> Fixnum
p 2.class #=> Fixnum
p "Hello".class #=> String
Now if we go into the docs for the *-method we find what each class expect:
http://ruby-doc.org/core-2.1.0/String.html#method-i-2A
http://ruby-doc.org/core-2.1.0/Array.html#method-i-2A
http://ruby-doc.org/core-2.1.0/Fixnum.html#method-i-2A
In there we find what will happen:
String expects an Integer. (num of times to repeat string)
Array expects an Integer or a String. (to repeat array x times or to join using string)
Fixnum expects an Numeric. (For simple multiplication)
Thus when you write "hello" * digicollect you are trying to call the multiplication method of a sting and pass it an Array, and the method simply do not know how to handle it (it will only accept Integers), that is why you get the error.

I should preface this by saying I don't get 2 when I type digicollect in irb ... I get [2]. This is a single element array with a value of 2. That's very different from the integer value 2.
String has no * operator for an array argument, and number has no * operator with a string argument. However, String does have * with a number argument, and digicollect[0] access the numeric value of that array element.

digicollect itself is not numeric, that's why you can't 'multiply' by it. It contains numbers, though, which is why "hello" * digicollect[0] works.
As for the 2 * "Hello" case, I believe that's a syntactic thing about the language - The string must come first and the integer second.

Related

Why is multiplication not always commutative in Ruby?

If x is a non-integer, I get this result:
x = "a"
x * 6 #=> aaaaaa
6 * x #=> TypeError: String can't be coerced into Fixnum
whereas if x is an integer:
x = 6
x * 6 #=> 36
6 * x #=> 36
It's strange that the operand order in multiplication matters if x is a non-integer, and not if x is an integer. Can someone explain what the rational is behind this? When x is a string, why must variable x precede the * operator to avoid raising an error?
You have a typo in your latter snippet: it should start with x = 6 (without quotes.)
Everything in Ruby is an object, including instances of String, Integer, even nil which is [the only] instance of NilClass.
That said, there is no just an operator *. It’s a plain old good method, declared on different classes, that is called by the operator * (thanks #SergioTulentsev for picky wording comment.) Here is a doc for String#*, other you might find yourself. And "a" * 6 is nothing else, than:
"a".*(6)
You might check the above in your console: it’s a perfectly valid Ruby code. So, different classes have different implementations of * method, hence the different results above.
You are trying three patterns here:
a. string * numeric
b. numeric * string
c. numeric * numeric
The behavior of a method and what arguments are required primarily depends on what is on the left side of the method (* in this case), on which the method is defined. No method (including *) is commutative per se.
String#* requires the first argument to be a numeric, which a. satisfies, and Numeric#* requires the first argument to be a numeric, which c. satisfies, and b. does not.
You need to understand what the method * does.1. That depends on the method's receiver. For "cat".*(3), "cat" is *'s receiver. For 1.*(3) (which, as explained later, can be written, 1*3) 1 is *'s receiver. The term "receiver" derives from OOP's concept of sending a message (method) to a receiver.
A method can be defined on an object (e.g., "cat" or 1) in one of two ways. The most common is that the method is an instance method defined on the receiver's class (e.g., * defined on "cat".class #=> String or 1.class #=> Integer. The second way, which is not applicable here, is that the method has been defined on the object's singleton class, provided the object has one. ("cat" has a singleton class but 1, being an immediate value, does not.)
When we see "cat".*(3), therefore, we look to the doc for String#* and conclude that
"cat".*(3) #=> "catcatcat"
For 1*(3), we look to Integer#*, which tells us that
1.*(3) #=> 3
Let's try another: [1,2,3].*(3), Because [1,2,3].class #=> Array we look to Array#* and conclude that
[1,2,3].*(3) #=> [1, 2, 3, 1, 2, 3, 1, 2, 3]
Note that this method has two forms, depending on whether its argument is an integer (as here) or a string. In the latter case
[1,2,3].*(' or ') #=> "1 or 2 or 3"
Many methods have different behaviors that depend on its arguments (and on whether an optional block is provided).
Lastly, Ruby allows us to use a shorthand with these three methods (and certain others with names comprised of characters that are not letters, numbers or underscores.):
"cat"*3 #=> "catcatcat"
"cat" * 3 #=> "catcatcat"
1*3 #=> 3
[1,2,3] * 3 #=> [1, 2, 3, 1, 2, 3, 1, 2, 3]
This shorthand is generally referred to as "syntactic sugar".
1 Ruby's method names are not restricted to words, such as "map", "upcase"
and so on. "*", "~", "[]" and "[]=", for example, are valid method names"

The commutative property of multiplication in Ruby

In ruby, I was messing around in the irb and found two code samples that should work the same but don't
"a" * 4 #this is "aaaa"
4 * "a" #this is "String can't be coerced into a Fixnum"
Doesn't this violate the commutative property of multiplication?
It does violate the commutative property, but that's not necessarily a problem, as the commutative property applies to the complex complex numbers in math. The reason "a" * 4 is not commutative in Ruby, as in most programming languages, is because a given type defines how it handles operators. So you could override the * operator for the String and Fixnum class (but that's a VERY VERY bad idea in practice):
class String
def *(other)
if other.is_a?(Numeric)
puts "The method was called on an instance of String"
end
end
end
class Fixnum
def *(other)
if other.is_a?(Numeric)
puts "The method was called on an instance of Fixnum"
end
end
end
So if you were to call
"a" * 4
Then it would print "The method was called on an instance of String" because that is equivalent to "a".*(4)
But this:
4 * "a"
Would print "The method was called on an instance of Fixnum" because 4 * "a" is equivalent to 4.*("a")
Here is a good article on operator overloading in Ruby.
Interesting side note: the commutative property actually doesn't apply to all numbers in math, the Quaterions and the Octonions both are not commutative.
Edit
If you wanted to, you could make the * operator commutative (but that would be a bad idea). You could then define * to swap the callee and the argument like such:
class Fixnum
def *(other)
other * self
end
end
That way, when ever you have 4 * "a" it would actually do this: "a" * 4. This would still work even if String#* was later redefined. Monkey patching can often be useful, but in this case it's a terrible idea, I don't recommend doing this, it's just a cool proof of concept.
"a" * 4 # repeat 'a' 4 times
4 * "a" # multiply 4 times the string 'a'
It's not multiplication unless two numbers are involved.
In Ruby, everything is an object. "a" is an object of class String, whereas 4 is an object of class Fixnum. So even numbers are objects.
And objects can have methods.
4 has a method called * that takes a number as an argument and multiplies 4 by that number. This method doesn't accept a string as an argument; it will unsuccessfully try to coerce the string to a number. (That's what explains your error message.)
"a" has a completely different method called * that takes a number as an argument. This method repeats the string multiple times.
Therefore:
4.*(4) # =>16
"a".*(4) # => "aaaa"
Ruby also lets you use a more succinct syntax for the * methods:
4 * 4 # =>16
"a" * 4 # => "aaaa"
But it's just a different way of writing the same thing.
No, it's a combination of precedence an the fact that they are both objects. What you are effectively doing in the 2nd version is 4.*("a"). Calling method '*' with parameter "a" on the Fixnum instance with value 4. So the String "a" cannot be coerced.

Division: Ruby no method error

I am trying to run this:
def ArithGeo(arr)
if arr[2]/arr[1] == arr[3]/arr[2]
return "Geometric"
else
return "Arithmetic"
end
end
print ArithGeo(STDIN.gets)
It comes back with line 2 having an "undefined method" when I run this in terminal.
Why? The array is all numbers when testing with [1,2,3,100]. (And yes I know that this will return "Arithmetic" when it isn't. I haven't gotten to that part yet.)
Also, is to_i necessary? If items in an array are already considered an integer, they're an integer, right? I also tried with to_i on each array item but it returned a "division by zero" error even when none of the items in the array were 0, and I wasn't using position 0.
One (or more) of the elements in your arr is a String.
irb(main):009:0> "string"/"another string"
NoMethodError: undefined method `/' for "string":String
When you call to_i on a String it becomes 0.
irb(main):013:0* "string".to_i
=> 0
When you divide by 0 you get an error because you can't do that.
irb(main):011:0> "string".to_i/"another string".to_i
ZeroDivisionError: divided by 0
You can fix your code by changing this line:
print ArithGeo(STDIN.gets)
to this:
print ArithGeo(STDIN.gets.strip.split(',').map(&:to_i))
Then enter your inputs like this:
1,2,3,100 # don't include the "[]" around the numbers
Since your input is of ruby syntax [1,2,3,100] you need to evaluate it.
def ArithGeo(arr)
puts "#{arr.class} , #{arr}"
if arr[2]/arr[1] == arr[3]/arr[2]
return "Geometric"
else
return "Arithmetic"
end
end
puts ArithGeo(eval STDIN.gets )
The input:
[1, 2, 3, 100]
The result:
Array , [1, 2, 3, 100]
Arithmetic
Also , I would recommend using floats to prevent integer rounding.
if arr[2].to_f/arr[1] == arr[3].to_f/arr[2]
Edit:
A much better (safer + more generic) is to use:
JSON.parse( array_string )
For example:
JSON.parse("[1 , 2]")
=> [1, 2]
JSON.parse("[1 , 2]").class
=> Array
And if you really want to be on the safe side , you'll need to add exception handling for JSON parsing errors.
You're passing a String to your method (IO.gets returns a string) when what you really want is an array of integers. If you just pass in this string, you will find that division is not defined for Strings. If you attempt to convert the input to an integer first, any leading non-numeric characters will cause the string to be converted to 0.
Try
arr = STDIN.gets.split(', ').map(&:to_i)
ArithGeo(arr)
It depends on your arr elements. Say, if arr elements are strings, then you will get a undefined method '/' for String (NoMethodError).
You need to make sure your arr elements are numbers i.e. integer or floats etc. on which the division (/) method is implemented.
Update
You can input the values comma separated and convert that string to an array using String#split method as I mentioned in the comment:
def ArithGeo(str)
arr = str.split(',').map(&:to_i) # split the values by comma and make them integer and put in array arr
# then you can use the following beause now your arr is an array, make sure you have at least 4 elements as you
# used index 3 in the calculation
if arr[2]/arr[1] == arr[3]/arr[2]
return "Geometric"
else
return "Arithmetic"
end
end
print ArithGeo(STDIN.gets)

Why can one multiply string with int with block as closure in Ruby?

While reading the book Programming Ruby, one example shows how blocks can be used as closure:
def nTimes(aThing)
return proc {|n| aThing * n}
end
p = nTimes("Hello ")
Now if we output the value of p.call(3) , it would be Hello Hello Hello
However, if our code was simply puts 3 * "Hello " , Ruby would complain about incompatible type.
Why? Thanks.
Your problem has nothing to do with closures or blocks. It is related to how operators are handled in Ruby.
On binary operations like * and +, the object to the left of the operand is the receiver of the method. So when you do "hello " * 3 it calls the * method on the class String and passes 3 as a parameter. The definition of String#* takes integers as parameters and returns self repeated that many times, hence the output "hello hello hello ".
But if you phrase it as 3 * "hello ", the * method of the Fixnum class is called, and "hello " is passed as a parameter. Fixnum#* doesn't know what to do with String parameters so you get an error.

In Ruby irb, can't access a number in a array like fashion

I tried this in irb:
x = 123456
Then I wanted to get a specific position of the number like:
puts x[2]
it returns 0
why is that?
The only (sensible) way to do this is to first convert it to a string then use the [] method:
x_str = x.to_s
puts x_str[0..2] #prints "12"
If you want to retrieve the position of a string within another string, use the index method
puts x_str.index('2') #prints 1
Fixnum does supply a [] method, but it's obviously not what you want.
In your code, it's returning 0 because that is the 3rd (zero-indexed) bit in the binary representation of 123456.

Resources