Ruby add / sum variable - ruby

I'm looking for an explanation as to why this works:
def somesum
x = 0
(1..10).each do |number|
x += number
end
puts x
end
whereas this does not work (undefined method '+' for nil class):
def somesum
(1..10).each do |number|
x += number
end
puts x
end
neither does this:
def somesum
(1..10).each do |number, x|
x += number
end
puts x
end

The difference why your first example works, is because you initialized x:
x = 0
whereas the last two example try to add 1 to nil in the first loop, which doesn't work, since nil has no method '+'.
Please consider, that your example is a bad implementation achieving the goal.
A better solution is to use the accumulator approach. For example Enumerable#inject:
(1..10).inject(0){ |sum, number| sum += number }
or even better:
(1..10).inject(:+)
which accumulates implicitly.
Enumerable#reduce works the same:
(1..10).reduce(:+)
For a better understanding, please go reading Iterators: inject and reject

In the second and third examples x has no value. Remember that:
x += number
is a shortening for:
x = x + number
so you're doing:
x = nil + number
and nil has no :+ method.

Related

How do you pass a range of values as arguments to a method?

I am calling a method I created and trying to pass a range of values as the arguments.
My code:
def prime_numbers (x)
i = 1
count = 0
until i > x
if x % i == 0
count += 1
end
i += 1
end
if count > 2
puts "count is: " + count.to_s
p x.to_s + " is not prime."
p false
elsif count == 2
puts "count is: " + count.to_s
p x.to_s + " is prime."
p true
end
end
prime_numbers (5)
puts
prime_numbers (25)
puts
prime_numbers (31)
puts
prime_numbers (1..100) #This is the one I care about that is throwing an error
Desired output:
count is: 2
"5 is prime."
true
count is: 3
"25 is not prime."
false
count is: 2
"31 is prime."
true
This would be desired for all the numbers within the range.
What I think I've done incorrectly or may still need to do:
I could use an array and somehow incorporate blocks to do all of this.
I'm missing something very simple in my syntax
Syntax in my parameter list needs to be changed
Thank you in advance for your time answering this.
Your method is named prime_numbers, but that is not exactly what it does. It is hard to come up with a good name: it does too much. That said, you could call it for every number in a range like this :
(1..100).each{|n| prime_numbers(n) }
In order to pass an array, you should define a method in a way that it can process an array.
In your code from what I can see is you are getting a parameter x and then applying an operator > to that which in case of a range will throw an error.
When (1..100) is passed as an argument x becomes an array what you might wanna do is something like this
def prime_numbers (x)
y = x.class == Range ? x : [x] # to make sure you have an array
y.each do |number|
...... you code here
end
end
PS you would want to replace number in the above example. Or you could rename your parameter x

Why does this Ruby code not return the expected answer?

I'm trying the list all factors of a number using the following method:
def find_factors(n)
factors = []
2.upto(n-1) {|x| factors << x if n % x == 0}
end
factor = find_factors(24)
puts factor
Its printing out the following:
2
instead of the list of factors! What am if doing incorrectly?
upto used with a block returns the receiver, which is 2.
A better way to write this would be:
def find_factors(n)
2.upto(n-1).select{|x| (n % x).zero?}
end
In ruby, whenever you see an array initialization before a loop, you can generally convert it to a more functional approach:
def find_factors(n)
2.upto(n-1).select{|x| n % x == 0}
end
This tends to be more compact and often more readable too.
You have to return factors at the end of your find_factors method:
def find_factors(n)
factors = []
2.upto(n-1) {|x| factors << x if n % x == 0}
factors
end

Yield something when random block of calculations passed

The part I don't understand is how to make this yield so that the elements in the array have the calculation, (which is specified in the block), done to them if block_given?, prior to their being added together.
For example, the calculation could be |x| x+3 (to add 3 to each of the elements), but I want this to work for any sort of manipulation of the elements, such as |x| x**3 or |x| x*5, so that the elements inmy_ary ([1,2,3]) are changed as specified by the calculation.
So essentially I'm asking what I need to do to the part of my code that reads yield array.each{|x|} if block_given? . what I was trying to do here is say that each element in the array should have whatever is stated in the block done to the element, so that it is changed.
What I am passing to the this is something along the lines of my_ary.sum(2) {|x| x **4}.
class MyArray
attr_reader :ary
def init(ary)
#ary = ary
end
def sum(init_val = 0)
yield ary.each{|x|} if block_given?
(#ary.inject(0){|x,y|x+y}) + init_val
end
end
class MyArray
attr_reader :ary
def initialize(ary)
#ary = ary
end
def sum n, &block
new_ary = #ary.collect &block # ary after executing block
ary_sum = new_ary.inject(0){|sum, x| sum+=x} # sum all elements of the array
return ary_sum + n
end
end
def nsum n, &block, here & saves the block (code between {} or do; end) to instance of Proc. It's basically your block of code saved to variable.
#ary.collect &block here, collect want block not proc so & change proc to the block. collect execute block for each element, and return new array.
inject - yields element to the block, add it to sum, and it is returned as sum variable. On the next iteration (next yielding to the block) sum will be last value of previous iteration.
[1,2,3].inject(0){|s, x| s+=x}
# sum = 0; x = 1;
# sum = 1; x = 2
# sum = 3; x = 3
# sum = 6
# inject returns 6 because there is no elements in the array

Syntax Error in Ruby, Unexpected Pipe Character in a Do

I'll try to be concise this time around! I'm still working Project Euler, this time back to #2. My real issue here is I'm terrible with Ruby. When I run the following code
x = 1
y = 2
sum = 2
while x >= 4_000_000 do |x|
sum += y if y % 2 == 0
z = x + y
x = x ^ y # xor magic
y = x ^ y # xor magic
x = x ^ y # xor magic
y = z
end
p sum
My interpreter kicks out the following output:
/Users/Andy/Documents/Programming/Ruby/ProjectEuler/P2.rb:4: syntax error, unexpected '|'
while x >= 4_000_000 do |x|
                         ^
I'm reading why's (Poignant) Guide to Ruby, and I'm pretty sure I have the pipe syntax correct for the Do. Could someone point out what I'm doing wrong here? I've tried messing around in a lot of different ways and am coming up short handed
while (x >= 4_000_000)
foo
end
You don't even have to pass in x, because it's accessible in the scope of the enclosing block.
while does not take a block. Remove the do |x| part.
while is not a method that takes a block, it is a ruby looping statement. It considers the part between the while and do (or newline) to be the logical test and the part between the do (or newline) and end keyword to be the loop body.
while x < 10 do x += 1; puts x; end
while x < 10
x += 1
puts x
end
Contrast this with something like the Array's each method which takes in a block. Here the each method calls your block for each element of the array (passed into the block as x)
[1,2,3].each do |x|
puts x
end
You accidentally combined the two, asking the while loop to call your code block with the loop counter to be passed in as x. That is not how while works... hence the parsing exception.
What an interesting question! It inspired me to take a shot at the problem, too. Here's my solution.
First, some preparatory work:
class Enumerator
def lazy_select
Enumerator.new do |y|
each do |el|
y.yield(el) if yield el
end
end
end
alias_method :lazy_find_all, :lazy_select
end
module Enumerable
def sum
reduce(:+)
end
end
module Math
ROOT5 = Math.sqrt(5)
PHI = 0.5 + ROOT5/2
def self.fibonacci(n)
Integer(0.5 + PHI**n/ROOT5)
end
end
class Integer
def fibonacci
Math.fibonacci(self)
end
end
Now an Enumerator which generates an infinite sequence of Fibonacci Numbers:
fibs = Enumerator.new do |y|
n = -1
loop do
y.yield (n += 1).fibonacci
end
end
And the nice thing is that we can now directly express the original problem statement in code:
Find the sum of all the even-valued terms in the sequence which do not exceed four million.
puts fibs.lazy_find_all(&:even?).take_while {|n| n <= 4_000_000 }.sum
I think that this is a much more Rubyish way to solve the problem. You write in your question that you are terrible with Ruby. But that's not actually the problem. The real problem is that you are good with C! In other words, the real problem is that you simply aren't writing Ruby, you are writing C with Ruby syntax.
Two good examples are:
y % 2 == 0
and
x = x ^ y
y = x ^ y
x = x ^ y
The Ruby way to write these would be
y.even?
and
x, y = y, x

More ruby-like solution to this problem?

I am learning ruby and practicing it by solving problems from Project Euler.
This is my solution for problem 12.
# Project Euler problem: 12
# What is the value of the first triangle number to have over five hundred divisors?
require 'prime'
triangle_number = ->(num){ (num *(num + 1)) / 2 }
factor_count = ->(num) do
prime_fac = Prime.prime_division(num)
exponents = prime_fac.collect { |item| item.last + 1 }
fac_count = exponents.inject(:*)
end
n = 2
loop do
tn = triangle_number.(n)
if factor_count.(tn) >= 500
puts tn
break
end
n += 1
end
Any improvements that can be made to this piece of code?
As others have stated, Rubyists will use methods or blocks way more than lambdas.
Ruby's Enumerable is a very powerful mixin, so I feel it pays here to build an enumerable in a similar way as Prime. So:
require 'prime'
class Triangular
class << self
include Enumerable
def each
sum = 0
1.upto(Float::INFINITY) do |i|
yield sum += i
end
end
end
end
This is very versatile. Just checking it works:
Triangular.first(4) # => [1, 3, 7, 10]
Good. Now you can use it to solve your problem:
def factor_count(num)
prime_fac = Prime.prime_division(num)
exponents = prime_fac.collect { |item| item.last + 1 }
exponents.inject(1, :*)
end
Triangular.find{|t| factor_count(t) >= 500} # => 76576500
Notes:
Float::INFINITY is new to 1.9.2. Either use 1.0/0, require 'backports' or do a loop if using an earlier version.
The each could be improved by first checking that a block is passed; you'll often see things like:
def each
return to_enum __method__ unless block_given?
# ...
Rather than solve the problem in one go, looking at the individual parts of the problem might help you understand ruby a bit better.
The first part is finding out what the triangle number would be. Since this uses sequence of natural numbers, you can represent this using a range in ruby. Here's an example:
(1..10).to_a => [1,2,3,4,5,6,7,8,9,10]
An array in ruby is considered an enumerable, and ruby provides lots of ways to enumerate over data. Using this notion you can iterate over this array using the each method and pass a block that sums the numbers.
sum = 0
(1..10).each do |x|
sum += x
end
sum => 55
This can also be done using another enumerable method known as inject that will pass what is returned from the previous element to the current element. Using this, you can get the sum in one line. In this example I use 1.upto(10), which will functionally work the same as (1..10).
1.upto(10).inject(0) {|sum, x| sum + x} => 55
Stepping through this, the first time this is called, sum = 0, x = 1, so (sum + x) = 1. Then it passes this to the next element and so sum = 1, x = 2, (sum + x) = 3. Next sum = 3, x = 3, (sum + x) = 6. sum = 6, x = 4, (sum + x) = 10. Etc etc.
That's just the first step of this problem. If you want to learn the language in this way, you should approach each part of the problem and learn what is appropriate to learn for that part, rather than tackling the entire problem.
REFACTORED SOLUTION (though not efficient at all)
def factors(n)
(1..n).select{|x| n % x == 0}
end
def triangle(n)
(n * (n + 1)) / 2
end
n = 2
until factors(triangle(n)).size >= 500
puts n
n += 1
end
puts triangle(n)
It looks like you are coming from writing Ocaml, or another functional language. In Ruby, you would want to use more def to define your methods. Ruby is about staying clean. But that might also be a personal preference.
And rather than a loop do you could while (faction_count(traingle_number(n)) < 500) do but for some that might be too much for one line.

Resources