Ruby: Am I using the correct scope? - ruby

I come from a JavaScript background and wrote this similar to how I would in javascript. I am writing it in Ruby.
This is a codewars exercise.
n being 0 and 1 returns 0.00 and 1.00 as expected. Every other positive natural number returns 0.
# Task:
# Your task is to write a function which returns the sum of following series upto nth term(parameter).
# Series: 1 + 1/4 + 1/7 + 1/10 + 1/13 + 1/16 +...
# Rules:
# You need to round the answer to 2 decimal places and return it as String.
# If the given value is 0 then it should return 0.00
# You will only be given Natural Numbers as arguments.
# Examples:
# SeriesSum(1) => 1 = "1.00"
# SeriesSum(2) => 1 + 1/4 = "1.25"
# SeriesSum(5) => 1 + 1/4 + 1/7 + 1/10 + 1/13 = "1.57"
def series_sum(n)
sum = 0
if n == 0
return 0.00
elsif n == 1
return 1.00
else
n.times do |i|
if i == 1
sum += 1
break
end
sum += 1/( 1 + (3 * (i - 1)) )
end
end
return sum
end
puts series_sum(0)
puts series_sum(1)
puts series_sum(2)
puts series_sum(4)
puts series_sum(5)

A couple of things to note:
- Ruby has reduce method that can sum up a list of numbers: https://apidock.com/ruby/Enumerable/reduce
- You don't need to explicitly return from your method. Ruby automatically returns the last statement in your method.
I've modified your solution, and this should work:
def series_sum(n)
if n > 1
sum = (1..n).inject { |sum, i| sum + (1/(1.to_f + (3 * (i - 1)))) }
else
sum = n
end
'%.2f' % sum
end
When you are expecting a decimal number in a division, always make sure that either the numerator or the denominator is in float, hence the reason for the 1.to_f.
'%.2f' is a string format to ensure the final answer is returned in 2 decimal places.

There are two parts to this question.
How to display an operation's result as a float value?
1/2 # this will give 0
1.0/2 # this will give 0.5
How to limit a float value to 2 decimal places?
You can use the round function
22.0/7 # this will give pi value - 3.142857142857143
(22.0/7).round(2) # this will give 3.14
The two answers above can be combined to get your answer. I would leave it as an exercise for you to come up with the exact code to solve your problem.

def series_sum(n)
return "0.00" if n.zero?
sprintf("%.2f", (0..n-1).sum { |m| 1.fdiv(3*m+1) }.round(2))
end
series_sum(0) #=> "0.00"
series_sum(1) #=> "1.00"
series_sum(2) #=> "1.25"
series_sum(3) #=> "1.39"
series_sum(4) #=> "1.49"
series_sum(5) #=> "1.57"
See Kernel#sprintf. One could alternatively use String%, which shares sprintf's formatting directives:
"%.2f" % (0..n-1).sum { |m| 1.fdiv(3*m+1) }.round(2)
I am not aware of the existence of a closed-form expression for this partial sum. Though not relevant to the question, this partial sum can be shown to be divergent.

Related

I don't understand this method

I'm a beginner in Ruby and I don't understand what this code is doing, could you explain it to me, please?
def a(n)
s = 0
for i in 0..n-1
s += i
end
s
end
def defines a method. Methods can be used to run the same code on different values. For example, lets say you wanted to get the square of a number:
def square(n)
n * n
end
Now I can do that with different values and I don't have to repeat n * n:
square(1) # => 1
square(2) # => 4
square(3) # => 9
= is an assignment.
s = 0 basically says, behind the name s, there is now a zero.
0..n-1 - constructs a range that holds all numbers between 0 and n - 1. For example:
puts (0..3).to_a
# 0
# 1
# 2
# 3
for assigns i each consecutive value of the range. It loops through all values. So first i is 0, then 1, then ... n - 1.
s += i is a shorthand for s = s + i. In other words, increments the existing value of s by i on each iteration.
The s at the end just says that the method (remember the thing we opened with def) will give you back the value of s. In other words - the sum we accumulated so far.
There is your programming lesson in 5 minutes.
This example isn't idiomatic Ruby code even if it is syntactically valid. Ruby hardly ever uses the for construct, iterators are more flexible. This might seem strange if you come from another language background where for is the backbone of many programs.
In any case, the program breaks down to this:
# Define a method called a which takes an argument n
def a(n)
# Assign 0 to the local variable s
s = 0
# For each value i in the range 0 through n minus one...
for i in 0..n-1
# ...add that value to s.
s += i
end
# The result of this method is s, the sum of those values.
s
end
The more Ruby way of expressing this is to use times:
def a(n)
s = 0
# Repeat this block n times, and in each iteration i will represent
# a value in the range 0 to n-1 in order.
n.times do |i|
s += i
end
s
end
That's just addressing the for issue. Already the code is more readable, mind you, where it's n.times do something. The do ... end block represents a chunk of code that's used for each iteration. Ruby blocks might be a little bewildering at first but understanding them is absolutely essential to being effective in Ruby.
Taking this one step further:
def a(n)
# For each element i in the range 0 to n-1...
(0..n-1).reduce |sum, i|
# ...add i to the sum and use that as the sum in the next round.
sum + i
end
end
The reduce method is one of the simple tools in Ruby that's quite potent if used effectively. It allows you to quickly spin through lists of things and compact them down to a single value, hence the name. It's also known as inject which is just an alias for the same thing.
You can also use short-hand for this:
def a(n)
# For each element in the range 0 to n-1, combine them with +
# and return that as the result of this method.
(0..n-1).reduce(&:+)
end
Where here &:+ is shorthand for { |a,b| a + b }, just as &:x would be short for { |a,b| a.x(b) }.
As you are a beginner in Ruby, let's start from the small slices.
0..n-1 => [0, n-1]. E.g. 0..3 => 0, 1, 2, 3 => [0, 3]
for i in 0.. n-1 => this is a for loop. i traverses [0, n-1].
s += i is same as s = s + i
So. Method a(n) initializes s = 0 then in the for loop i traverse [0, n - 1] and s = s + i
At the end of this method there is an s. Ruby omits key words return. so you can see it as return s
def a(n)
s = 0
for i in 0..n-1
s += i
end
s
end
is same as
def a(n)
s = 0
for i in 0..n-1
s = s + i
end
return s
end
a(4) = 0 + 1 + 2 + 3 = 6
Hope this is helpful.
The method a(n) calculates the sums of the first n natural numbers.
Example:
when n=4, then s = 0+1+2+3 = 6
Let's go symbol by symbol!
def a(n)
This is the start of a function definition, and you're defining the function a that takes a single parameter, n - all typical software stuff. Notably, you can define a function on other things, too:
foo = "foo"
def foo.bar
"bar"
end
foo.bar() # "bar"
"foo".bar # NoMethodError
Next line:
s = 0
In this line, you're both declaring the variable s, and setting it's initial value to 0. Also typical programming stuff.
Notably, the value of the entire expression; s = 0, is the value of s after the assignment:
s = 0
r = t = s += 1 # You can think: r = (t = (s += 1) )
# r and t are now 1
Next line:
for i in 0..n-1
This is starting a loop; specifically a for ... in ... loop. This one a little harder to unpack, but the entire statement is basically: "for each integer between 0 and n-1, assign that number to i and then do something". In fact, in Ruby, another way to write this line is:
(0..n-1).each do |i|
This line and your line are exactly the same.
For single line loops, you can use { and } instead of do and end:
(0..n-1).each{|i| s += i }
This line and your for loop are exactly the same.
(0..n-1) is a range. Ranges are super fun! You can use a lot of things to make up a range, particularly, time:
(Time.now..Time.new(2017, 1, 1)) # Now, until Jan 1st in 2017
You can also change the "step size", so that instead of every integer, it's, say, every 1/10:
(0..5).step(0.1).to_a # [0.0, 0.1, 0.2, ...]
Also, you can make the range exclude the last value:
(0..5).to_a # [0, 1, 2, 3, 4, 5]
(0...5).to_a # [0, 1, 2, 3, 4]
Next line!
s += i
Usually read aloud a "plus-equals". It's literally the same as: s = s + 1. AFAIK, almost every operator in Ruby can be paired up this way:
s = 5
s -= 2 # 3
s *= 4 # 12
s /= 2 # 6
s %= 4 # 2
# etc
Final lines (we'll take these as a group):
end
s
end
The "blocks" (groups of code) that are started by def and for need to be ended, that's what you're doing here.
But also!
Everything in Ruby has a value. Every expression has a value (including assignment, as you saw with line 2), and every block of code. The default value of a block is the value of the last expression in that block.
For your function, the last expression is simply s, and so the value of the expression is the value of s, after all is said and done. This is literally the same as:
return s
end
For the loop, it's weirder - it ends up being the evaluated range.
This example may make it clearer:
n = 5
s = 0
x = for i in (0..n-1)
s += i
end
# x is (0..4)
To recap, another way to write you function is:
def a(n)
s = 0
(0..n-1).each{ |i| s = s + i }
return s
end
Questions?

Can I implement round half to even?

I need to do round half to even on floats, i.e.,
if the value is half-way between two integers (tie-breaking, fraction part of y is exactly 0.5) round to the nearest even integer,
else, standard round (which is Round to nearest Integer in Ruby).
These are some results, for example:
0.5=>0
1.49=>1
1.5=>2
2.5=>2
2.51=>3
3.5=>4
The BigDecimal class has the rounding mode half to even already implemented. You just have to set the ROUND_MODE to :half_even with BigDecimal.mode method:
require 'bigdecimal'
def round_half_to_even(float)
BigDecimal.mode(BigDecimal::ROUND_MODE, :half_even)
BigDecimal.new(float, 0).round
end
Or by using the round with some arguments:
require 'bigdecimal'
def round_half_to_even(float)
BigDecimal.new(float, 0).round(0, :half_even).to_i
end
Please note that BigDecimal#round returns an Integer when used without arguments, but a BigDecimal when used with arguments. Therefore the need to call to_i in the second example but not in the first.
I would reopen the Float class to create a round_half_to_even function :
class Float
def round_half_to_even(precision)
if self % 1 == 0.5
floor = self.to_i.to_f
return floor % 2 == 0 ? floor : floor + 1
else
return self.round(precision)
end
end
end
def round_half_to_even f
q, r = f.divmod(2.0)
q * 2 +
case
when r <= 0.5 then 0
when r >= 1.5 then 2
else 1
end
end
round_half_to_even(0.5) # => 0
round_half_to_even(1.49) # => 1
round_half_to_even(1.5) # => 2
round_half_to_even(2.5) # => 2
round_half_to_even(2.51) # => 3
round_half_to_even(3.5) # => 4
You could do the following:
def round_half_to_even(f)
floor = f.to_i
return f.round unless f==floor+0.5
floor.odd? ? f.ceil : floor
end
round_half_to_even(2.4) #=> 2
round_half_to_even(2.6) #=> 3
round_half_to_even(3.6) #=> 4
round_half_to_even(2.5) #=> 2
round_half_to_even(3.5) #=> 4

Syntax error? Ruby bug? Issue with instance variable incrementing with += 1?

def isPrime?(num)
i = 2
#isFalse = 0
while i < num
divisible = ((num % i) == 0)
if divisible
#isFalse += 1
return false
end
i += 1
end
true
end
def primes(max)
startTime = Time.now
(2..max).each do |p|
puts "#{p} #{isPrime?(p)}"
end
endTime = Time.now
puts "--------------------------------------------------"
puts " FALSE values in range from (2 thru #{max}): #{#isFalse} \n TRUE values in range from (2 thru #{max}): #{max-1-#isFalse}"
puts "\nTotal time to calculate is #{endTime - startTime} seconds!"
end
primes(10)
isPrime? checks if a given number is a prime number.
primes loads a range of numbers and checks if each is a prime.
I want to know how many numbers are prime within the range and how many aren't.
I added #isFalse += 1 thinking I can increment each time false is returned so that I can determine how many numbers in the range are false and use this to subtract from max to get how many numbers are true.
Entire code is working correctly except #isFalse is not properly incrementing. Why is that? Thanks for the help.
--UPDATE--
My Output: added puts "About to increment #isFalse" before #isFalse += 1
2 true
3 true
About to increment #isFalse
4 false
5 true
About to increment #isFalse
6 false
7 true
About to increment #isFalse
8 false
About to increment #isFalse
9 false
About to increment #isFalse
10 false
--------------------------------------------------
FALSE values in range from (2 thru 10): 1
TRUE values in range from (2 thru 10): 8
Each time isPrime? is called, #isFalse is reset to 0. So the result of #isFalse being 1 is from the last time isPrime? was called (with num equal to 10, incrementing #isFalse to 1).
It seems that you are trying to find out the number of primes in that range using #isFalse. If that is the case, you should instead use the following modification of your code (although, I do not recommend checking for primes in this way, and the code is really inefficient):
Basically, I removed the instance variable #isFalse altogether, and checked whether a number is prime or not in your second method, instead. The code is much cleaner that way, and really does what you intend it to do.
The problem with your code is that #isFalse is being reset to 0 everytime your first method isPrime? was being called, and hence, does not properly reflect the number of primes in the given range.
def isPrime?(num)
i = 2
while i < num
divisible = ((num % i) == 0)
return false if divisible
i += 1
end
true
end
def primes(max)
startTime = Time.now
is_prime = 0
(2..max).each do |p|
if isPrime?(p)
is_prime += 1
puts p
end
endTime = Time.now
puts "--------------------------------------------------"
puts " FALSE values in range from (2 thru #{max}): #{is_prime} \n TRUE values in range from (2 thru #{max}): #{max-1-is_prime}"
puts "\nTotal time to calculate is #{endTime - startTime} seconds!"
end
primes(10)
As your question has been answered, I would like to suggest a more Ruby-like solution:
You want the method is_prime? to do nothing other than determine if num is prime:
def is_prime?(num)
(2...num).each {|i| return false if num % i == 0}
true
end
Do your counting of primes in the method nbr_primes.
def nbr_primes(max)
return false if max < 2
(2..max).reduce(0) {|tot, i| tot + (is_prime?(i) ? 1 : 0)}
end
p nbr_primes(20) # => 8
A few points:
I removed the references to time and the output formatting as they are not central to the question.
It's a Ruby convention to name methods with lower case letters and underscores.
(2...num), because it has three dots, is the sequence from 2 to (and including) num - 1. We could instead write (2..num-1) (two dots), which is favored by some.
(2..max).reduce(0) {|tot, i|...} iterates over i from 2 to and including max. tot, which is reduce's accumulator, is incremented by 1 for each number between 2 and max that is found to be prime. The expression returns the value of tot, which in turn is returned by the method nbr_primes. inject is a synonym for reduce.
In checking whether a number n is prime, you only have to check if its divisible by numbers up to Math.sqrt(n).to_i.
With require 'prime', you don't have to reinvent the wheel. For example, Prime.prime?(7) #=> true, and Prime.take_while {|p| p <= 10}.size #=> [2, 3, 5, 7].size + 1 # => 4.
#isFalse = 0 is inside your isPrime? method. Get it out of there!

The 'upto' method in Ruby

I'm learning Ruby, and there has been a bit of talk about the upto method in the book from which I am learning. I'm confused. What exactly does it do?
Example:
grades = [88,99,73,56,87,64]
sum = 0
0.upto(grades.length - 1) do |loop_index|
sum += grades[loop_index]
end
average = sum/grades.length
puts average
Let's try an explanation:
You define an array
grades = [88,99,73,56,87,64]
and prepare a variable to store the sum:
sum = 0
grades.length is 6 (there are 6 elements in the array), (grades.length - 1) is 5.
with 0.upto(5) you loop from 0 to 5, loop_index will be 0, then 1...
The first element of the array is grades[0] (the index in the array starts with 0).
That's why you have to subtract 1 from the number of elements.
0.upto(grades.length - 1) do |loop_index|
Add the loop_index's value to sum.
sum += grades[loop_index]
end
Now you looped on each element and have the sum of all elements of the array.
You can calculate the average:
average = sum/grades.length
Now you write the result to stdout:
puts average
This was a non-ruby-like syntax. Ruby-like you would do it like this:
grades = [88,99,73,56,87,64]
sum = 0
grades.each do |value|
sum += value
end
average = sum/grades.length
puts average
Addendum based on Marc-Andrés comment:
You may use also inject to avoid to define the initial sum:
grades = [88,99,73,56,87,64]
sum = grades.inject do |sum, value|
sum + value
end
average = sum / grades.length
puts average
Or even shorter:
grades = [88,99,73,56,87,64]
average = grades.inject(:+) / grades.length
puts average
From http://www.ruby-doc.org/docs/ProgrammingRuby/html/ref_c_integer.html#upto:
upto int.upto( anInteger ) {| i | block }
Iterates block, passing in integer values from int up to and
including anInteger.
5.upto(10) { |i| print i, " " }
produces:
5 6 7 8 9 10
Upto executes the block given once for each number from the original number "upto" the argument passed. For example:
1.upto(10) {|x| puts x}
will print out the numbers 1 through 10.
It is just another way to do a loop/iterator in Ruby. It says do this action n times based on i being the first number the the number in parens as the limit.
My example would have been this:
1.upto(5) { |i| puts "Countup: #{i}" }
So what you're actually doing here is saying, I want to count up from 1 to the number 5, that's specifically what this part is saying:
1.upto(5)
The latter part of code (a block) is just outputting the iteration of going through the count from 1 up to 5. This is the output you might expect to see:
Countup: 1
Countup: 2
Countup: 3
Countup: 4
Countup: 5
Note: This can be written is another way if you're using multilines:
1.upto(5) do |i|
puts "Countup: #{i}"
end
Hope this helps.
An alternative that looks more like Ruby to me is
require 'descriptive_statistics'
grades=[88,99,73,56,87,64]
sum = grades.sum
average = grades.mean
sd = grades.standard_deviation
Of course it depends what you're doing.

Iterate over an infinite sequence in Ruby

I am trying to solve Project Euler problem #12:
The sequence of triangle numbers is generated by adding the natural
numbers. So the 7th triangle number
would be 1 + 2 + 3 + 4 + 5 + 6 + 7 =
28. The first ten terms would be:
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...
Let us list the factors of the first seven triangle numbers:
1: 1
3: 1,3
6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28
We can see that 28 is the first triangle number to have over five
divisors.
What is the value of the first triangle number to have over five
hundred divisors?
Here's the solution that I came up with using Ruby:
triangle_number = 1
(2..9_999_999_999_999_999).each do |i|
triangle_number += i
num_divisors = 2 # 1 and the number divide the number always so we don't iterate over the entire sequence
(2..( i/2 + 1 )).each do |j|
num_divisors += 1 if i % j == 0
end
if num_divisors == 500 then
puts i
break
end
end
I shouldn't be using an arbitrary huge number like 9_999_999_999_999_999. It would be better if we had a Math.INFINITY sequence like some functional languages. How can I generate a lazy infinite sequence in Ruby?
Several answers are close but I don't actually see anyone using infinite ranges. Ruby supports them just fine.
Inf = Float::INFINITY # Ruby 1.9
Inf = 1.0/0 # Ruby before 1.9
(1..Inf).include?(2305843009213693951)
# => true
(1..Inf).step(7).take(3).inject(&:+)
# => 24.0
In your case
(2..Inf).find {|i| ((2..( i/2 + 1 )).select{|j| i % j == 0}.count+2)==42 }
=> 2880
Your brute force method is crude and can, potentially, take a very long time to finish.
In Ruby >= 1.9, you can create an Enumerator object that yields whatever sequence you like. Here's one that yields an infinite sequence of integers:
#!/usr/bin/ruby1.9
sequence = Enumerator.new do |yielder|
number = 0
loop do
number += 1
yielder.yield number
end
end
5.times do
puts sequence.next
end
# => 1
# => 2
# => 3
# => 4
# => 5
Or:
sequence.each do |i|
puts i
break if i >= 5
end
Or:
sequence.take(5).each { |i| puts i }
Programming Ruby 1.9 (aka "The Pickaxe Book"), 3rd. ed., p. 83, has an example of an Enumerator for triangular numbers. It should be easy to modify the Enumerator above to generate triangular numbers. I'd do it here, but that would reproduce the example verbatim, probably more than "fair use" allows.
Infinity is defined on Float (Ruby 1.9)
a = Float::INFINITY
puts a #=> Infinity
b = -a
puts a*b #=> -Infinity, just toying
1.upto(a) {|x| break if x >10; puts x}
Currrent versions of Ruby support generators heavily:
sequence = 1.step
In Ruby 2.6 this becomes much easier:
(1..).each {|n| ... }
Source: https://bugs.ruby-lang.org/issues/12912
This would be best as a simple loop.
triangle_number = 1
i = 1
while num_divisors < 500
i += 1
triangle_number += i
# ...
end
puts i
As Amadan mentioned you can use closures:
triangle = lambda { t = 0; n = 1; lambda{ t += n; n += 1; t } }[]
10.times { puts triangle[] }
Don't really think it is much slower than a loop. You can save state in class object too, but you will need more typing:
class Tri
def initialize
#t = 0
#n = 1
end
def next
#t += n
#n += 1
#t
end
end
t = Tri.new
10.times{ puts t.next }
Added:
For those who like longjmps:
require "generator"
tri =
Generator.new do |g|
t, n = 0, 1
loop do
t += n
n += 1
g.yield t
end
end
puts (0..19).map{ tri.next }.inspect
Building on Wayne's excellent answer and in the Ruby spirit of doing things with the least number of characters here is a slightly updated version:
sequence = Enumerator.new { |yielder| 1.step { |num| yielder.yield num } }
Obviously, doesn't solve the original Euler problem but is good for generating an infinite sequence of integers. Definitely works for Ruby > 2.0. Enjoy!
On Christmas Day 2018, Ruby introduced the endless range, providing a simple new approach to this problem.
This is implemented by ommitting the final character from the range, for example:
(1..)
(1...)
(10..)
(Time.now..)
Or to update using Jonas Elfström's solution:
(2..).find { |i| ((2..( i / 2 + 1 )).select { |j| i % j == 0 }.count + 2) == 42 }
Hope this proves useful to someone!
I believe that fibers (added in Ruby 1.9 I believe) may be close to what you want. See here for some information or just search for Ruby Fibers

Resources