How to understand objects, methods and arguments in Ruby calculations - ruby

While learning Ruby gotchas, I am getting different results with some calculations in IRB:
1-2-7-2 # => -10
1.-2.-7.-2 # => 4
1.-2.-7.-2.-4 # => 8
1.-2.-7.-2.+4 # => 0
1.-(2).-(7).-(2) # => -10
Possibly it is related to methods and arguments? I am trying to wrap my head around this.

You've chosen an interesting way to approach calculations.
I guess you are trying to omit zeros in your expression 1.-2.-7.-2 which will return -10 if you write it as 1.0 - 2.0 - 7.0 - 2.
The way you're getting 4 is because 1.- construction calls -() method because everything is an object in Ruby and then you pass an argument to the function.
In your case it will be parsed as
1.-( 2.-( 7.-(2) ) )
# if we try to unwrap
a = 7.-(2) # => 5
b = 2.-(a) # => -3
1.-(-3) # (or 1 + 3) => 4

Related

Can I use the .each Method to Solve this sum problem?

still new to Ruby. Noob question, please bear with me. And thank you ahead of time.
I love the .each method over something like the while loop. The while loop is confusing for me. I love the neatness of the .each method. Can I use the .each method to solve this question below? I'm pulling my hair out trying to figure out if I can use this style loop.
Thank you for your help!
def sum_nums(max)
puts sum_nums(4) # => 10, because 1 + 2 + 3 + 4 = 10
puts sum_nums(5) # => 15
Yes , you can use the .each method to solve this question. Pulling hairs out is not the way however. Try initializing a variable to 0 outside the each- block, and add all values in the block to that variable.
So to answer the OP (and borrowing shamelessly from all the other answers)
def sum_nums(n)
(1..n).sum
end
puts sum_nums(5)
# => 15
Here are a few options of how to sum all numbers from 1 to n in Ruby:
1.upto(4).reduce(:+) # => 10
1.upto(5).reduce(:+) # => 15
(1..4).reduce(:+) # => 10
(1..5).reduce(:+) # => 15
# could use `each`, but it is doing nothing here.
(1..4).each.reduce(:+) # => 10
(1..5).each.reduce(:+) # => 15
# same thing with `each`, but keeping track of the sum manually
sum = 0
(1..4).each do |i|
sum += i
end
# i => 10
Basically you get an Enumerable (iterator/collection abstraction) that spans over the things you would like enumerate. In our case we would like to go from 1 to 4. We can get an Enumerable for that either by calling Integer#upto method (like so: 1.upto(4), or by using Range (like so (1..4)). Then we can use any Enumerable methods on the collection/iterator.
Enumerable#each simply calls a block for every element (and when called without a block, essentially does nothing, just returns the same Enumerable), but Enumerable also has built-in functions for finding minimum, maximum, reducing (in our case we're doing the sum, so reduce fits), etc. For more detailed information see docs for Enumerable.
An example way that comes into my mind.
def sum_nums(max)
sum = 0
array = Array.new(max) { |i| (i + 1) }
array.each { |element| sum += element }
puts sum
end
sum_nums(4) # => 10
sum_nums(5) # => 15

How do I destructure a range in Ruby?

Is it possible to use destructuring in ruby to extract the end and beginning from a range?
module PriceHelper
def price_range_human( range )
"$%s to $%s" % [range.begin, range.end].map(:number_to_currency)
end
end
I know that I can use array coercion as a really bad hack:
first, *center, last = *rng
"$%s to $%s" % [first, last].map(:number_to_currency)
But is there a syntactical way to get begin and end without actually manually creating an array?
min, max = (1..10)
Would have been awesome.
You can use minmax to destructure ranges:
min, max = (1..10).minmax
min # => 1
max # => 10
If you are using Ruby before 2.7, avoid using this on large ranges.
The beginning and end? I'd use:
foo = 1..2
foo.min # => 1
foo.max # => 2
Trying to use destructuring for a range is a bad idea. Imagine the sizes of the array that could be generated then thrown away, wasting CPU time and memory. It's actually a great way to DOS your own code if your range ends with Float::INFINITY.
end is not the same as max: in 1...10, end is 10, but max is 9
That's because start_val ... end_val is equivalent to start_val .. (end_val - 1):
start_value = 1
end_value = 2
foo = start_value...end_value
foo.end # => 2
foo.max # => 1
foo = start_value..(end_value - 1)
foo.end # => 1
foo.max # => 1
max reflects the reality of the values actually used by Ruby when iterating over the range or testing for inclusion in the range.
In my opinion, end should reflect the actual maximum value that will be considered inside the range, not the value used at the end of the definition of the range, but I doubt that'll change otherwise it'd affect existing code.
... is more confusing and leads to increased maintenance problems so its use is not recommended.
No, Until I am proven incorrect by Cary Swoveland, Weekly World News or another tabloid, I'll continue believing without any evidence that the answer is "no"; but it's easy enough to make.
module RangeWithBounds
refine Range do
def bounds
[self.begin, self.end]
end
end
end
module Test
using RangeWithBounds
r = (1..10)
b, e = *r.bounds
puts "#{b}..#{e}"
end
Then again, I'd just write "#{r.begin.number_to_currency}..#{r.end.number_to_currency}" in the first place.
Amadan's answer is fine. you just need to remove the splat (*) when using it since it is not needed
eg,
> "%s to %s" % (1..3).bounds.map{|x| number_to_currency(x)}
=> "$1.00 to $3.00"

Why is a space allowed between minus and a number?

These are expected:
-3 # => -3
0 - 3 # => -3
But what is happening here:
- 3 # => -3
My first thoughts was - is a method on the implied self, i.e. self.-(3), so defined on Kernel or Object. But trying this results in NoMethodError: undefined method.
Ruby has a pretty forgiving syntax and allows things like this. That's parsed as a unary minus operator. It negates whatever's on the right hand side.
Also similar:
-(3)
# => -3
-(-(-3))
# => -3
- (3)
# => -3
It's similar to how you can omit braces on method calls: foo x is valid, but foo(x) is implied. You can also do foo (x) though that can lead to ambiguity so it's generally frowned upon.
As Dave Newton points out, internally this is actually:
3.send(:-#)

What does the bracket operator do to a FixNum in Ruby?

Coming from Python I find the following behaviour very surprising:
irb(main):211:0> x= 33
=> 33
irb(main):212:0> x[0]
=> 1
irb(main):213:0> x[1]
=> 0
irb(main):214:0> x[2]
=> 0
Is there a rationale/philosophy for not raising an error in this example?
The bracket operator gives you the nth bit of the binary representation:
http://ruby-doc.org/core-2.1.2/Fixnum.html#method-i-5B-5D
You might be a little confused about what this is doing internally, but that's normal when dealing with Ruby because it's quite unlike other scripting languages. Unless you've used SmallTalk it might even seem insane.
When Ruby sees the following code:
x = 6
x[1]
What it's actually doing is this:
x.send(:[], 6) # Send :[] method call to x with arguments [ 6 ]
The x object is free to interpret that however it wants, and the behaviour is typically (though not always) defined by the class x belongs to if x is a normal instance.
In this case it's returning the bit at a given index, equivalent to x & (1 << 6) >> 6.
Sometimes the [] method does several things:
string = "brackets"
# Retrieve a single character
string[1]
# => "r"
# Retrieve a substring
string[5,2]
# => "et"
# Perform a pattern match
string[/[^aeiou]+/]
# => "br"
This also does some pretty crazy things since you can apply it to a Proc as well:
fn = lambda { |x| x + 1 }
# Conventional (explicit) call
fn.call(2)
# => 3
# Square bracket method
fn[5]
# => 6
Since Ruby leans very heavily on Duck Typing, this means that you can write a Proc to fill in where you'd normally have a Hash or an Array and the method receiving your object is none the wiser.
It's this flexibility in leaving the meaning of x[...] for your own class instance x up to you that makes it pretty powerful.
For example:
class Bracketeer
def [](i)
"%d brackets" % i
end
end
bracketeer = Bracketeer.new
bracketeer[6]
# => "6 brackets"
This simple notation often comes in handy when you're trying to create a minimal interface for a class of yours. In many cases you can use something simple like [] to replace what would be a more verbose method like find_by_id or cache_fetch.
Certainly. You'll find that the manual is quite illuminating.
This is returning the binary bit for the bit position value as a zero or one.
It is returning the n'th bit as rightfully observed by #msergeant.
What this means is, for the number 33, its binary representation is:
Index : [7][6][5][4] [3][2][1][0]
Bits : 0 0 1 0 0 0 0 1
Which explains the output:
irb(main):212:0> x[0]
=> 1
irb(main):213:0> x[1]
=> 0
irb(main):214:0> x[2]
=> 0

Ruby: method finder gem example

I found this great gem 'method finder' that I'm trying to use to help improve my understanding of Ruby, problem is that I don't really get it. It gives this example from the docs. The method 'unknown' is supposed to replace whatever method will give the result in the surrounding code, but what is this example telling us?
>> 10.find_method { |n| n.unknown(3) == 1 }
=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", "Fixnum#[]", "Integer#gcd", "Fixnum#modulo", "Numeric#remainder"]
It's telling you exactly what you asked it for: all the methods on 10 that return 1 when passed 3:
>> 10 % 3
=> 1
>> 10 <=> 3
=> 1
>> 10 >> 3
=> 1
>> 10[3]
=> 1
>> …

Resources