Combining multiple methods into one - ruby

I am wondering if there was a way to combine multiple methods into one using Proc.new, lambda, or another method.
Also there is something wrong with my code below.
def multiples(n,p)
(n..p).each do |e|
puts e if e%2 == 0 or e%3 == 0
end
end
def summing(n)
sum = 0
n.each { |x| puts sum+=x }
end
It provides the correct answer when I test them individually like multiples(2,43) or summing([2,6,5,4]), but when I combine the two like summing(multiples(0,10)), I get the wrong answer.
If somebody could help me, that would be great.

The below should work..
def multiples(n,p)
(n..p).map do |e|
e if e%2 == 0 or e%3 == 0
end.compact
end
def summing(n)
sum = 0
n.each { |x| p sum+=x }
end
summing(multiples(0,10))
# >> 0
# >> 2
# >> 5
# >> 9
# >> 15
# >> 23
# >> 32
# >> 42
Array#each will not help you,for your task,as it returns the receiver when finished.

Jamaal,
You want summing to return sum (rather than n), so you need sum at the end:
def summing(n)
sum = 0
n.each { |x| puts sum += x}
sum
end

Related

Ruby: Iterate the result from method using block

Now I have a ruby like this:
def fizzbuzz(numSize)
result = []
1.upto(numSize) do |num|
if num % 15 == 0
result << "FizzBuzz"
elsif num % 3 == 0
result << "Fizz"
elsif num % 5 == 0
result << "Buzz"
else
result << num.to_s
end
end
result
end
print fizzbuzz(10) {|item| "-#{i1tem}-"}
If I want to print the result like this:
["-1-", "-2-", "-Fizz-", "-4-", "-Buzz-", "-Fizz-", "-7-", "-8-", "-Fizz-", "-Buzz-"]
What can I modify my code in method fizzbuzz if I can not change the code:
print fizzbuzz(10) {|item| "-#{i1tem}-"}
Thanks
That block is being given to your method, but you're not making use of it. That's an easy fix:
def fizzbuzz(numSize, &block)
# ... (existing code) ...
result.map(&block)
end
Where that transforms the result value using map.
Note this requires fixing the typo in your print block which is i1tem not item.
It's also worth noting you should avoid this pattern:
x = [ ]
y.each do |v|
x << f(v)
end
x
That's just a long-winded version of this:
y.map do |v|
f(v)
end
Where when you're transforming on a 1:1 basis from the source just use map.
In your case that reduces the code to this more minimal form that has a lot less repetition:
def fizzbuzz(numSize, &block)
1.upto(numSize).map do |num|
if num % 15 == 0
"FizzBuzz"
elsif num % 3 == 0
"Fizz"
elsif num % 5 == 0
"Buzz"
else
num.to_s
end
end.map(&block)
end

Euler 23 in Ruby

All right. I think I have the right idea to find the solution to Euler #23 (The one about finding the sum of all numbers that can't be expressed as the sum of two abundant numbers).
However, it is clear that one of my methods is too damn brutal.
How do you un-brute force this and make it work?
sum_of_two_abunds?(num, array) is the problematic method. I've tried pre-excluding certain numbers and it's still taking forever and I'm not even sure that it's giving the right answer.
def divsum(number)
divsum = 1
(2..Math.sqrt(number)).each {|i| divsum += i + number/i if number % i == 0}
divsum -= Math.sqrt(number) if Math.sqrt(number).integer?
divsum
end
def is_abundant?(num)
return true if divsum(num) > num
return false
end
def get_abundants(uptonum)
abundants = (12..uptonum).select {|int| is_abundant?(int)}
end
def sum_of_two_abunds?(num, array)
#abundant, and can be made from adding two abundant numbers.
array.each do |abun1|
array.each do |abun2|
current = abun1+abun2
break if current > num
return true if current == num
end
end
return false
end
def non_abundant_sum
ceiling = 28123
sum = (1..23).inject(:+) + (24..ceiling).select{|i| i < 945 && i % 2 != 0}.inject(:+)
numeri = (24..ceiling).to_a
numeri.delete_if {|i| i < 945 && i % 2 != 0}
numeri.delete_if {|i| i % 100 == 0}
abundants = get_abundants(ceiling)
numeri.each {|numerus| sum += numerus if sum_of_two_abunds?(numerus, abundants) == false}
return sum
end
start_time = Time.now
puts non_abundant_sum
#Not enough numbers getting excluded from the total.
duration = Time.now - start_time
puts "Took #{duration} s "
Solution 1
A simple way to make it a lot faster is to speed up your sum_of_two_abunds? method:
def sum_of_two_abunds?(num, array)
array.each do |abun1|
array.each do |abun2|
current = abun1+abun2
break if current > num
return true if current == num
end
end
return false
end
Instead of that inner loop, just ask the array whether it contains num - abun1:
def sum_of_two_abunds?(num, array)
array.each do |abun1|
return true if array.include?(num - abun1)
end
false
end
That's already faster than your Ruby code, since it's simpler and running faster C code. Also, now that that idea is clear, you can take advantage of the fact that the array is sorted and search num - abun1 with binary search:
def sum_of_two_abunds?(num, array)
array.each do |abun1|
return true if array.bsearch { |x| num - abun1 <=> x }
end
false
end
And making that Rubyish:
def sum_of_two_abunds?(num, array)
array.any? do |abun1|
array.bsearch { |x| num - abun1 <=> x }
end
end
Now you can get rid of your own special case optimizations and fix your incorrect divsum (which for example claims that divsum(4) is 5 ... you should really compare against a naive implementation that doesn't try any square root optimizations).
And then it should finish in well under a minute (about 11 seconds on my PC).
Solution 2
Or you could instead ditch sum_of_two_abunds? entirely and just create all sums of two abundants and nullify their contribution to the sum:
def non_abundant_sum
ceiling = 28123
abundants = get_abundants(ceiling)
numeri = (0..ceiling).to_a
abundants.each { |a| abundants.each { |b| numeri[a + b] = 0 } }
numeri.compact.sum
end
That runs on my PC in about 3 seconds.

How do I calculate the factorial of a number in Ruby?

Alright, so I asked an earlier question on my syntax error. I got rid of the errors, but the program doesn't do what it was intended to do. My math is wrong and doesn't find the number of trailing zeros. Here is my code:
num = " "
a = 0
sumOfFact = 1
def factorial
num = gets.to_i
a = num
(1..num).each do |a|
if a != 1
sumOfFact *= a
a -= 1
else
break
end
end
end
for c in 1..sumOfFact
if sumOfFact / c == 10
zeros += 1
end
end
factorial()
puts sumOfFact
puts zeros
Well, first, you should do the gets outside your method. Your method should accept a param. Second, why do you need the condition?
You want the multiplication from 1 to n to get the factorial. You should get started with this:
def factorial(n)
total = 1
(1..n).each do |n|
total *= n
end
total
end
puts factorial(gets.to_i)
Next is factorial with inject in case you want to learn new syntax :-)
def factorial(n)
n == 0? 1 : (1..n).inject(1) { |total, i| total*= i; total }
end
puts factorial(gets.to_i)
As #pjs commented below, here's a beautiful way of doing factorial!
def factorial(n)
n == 0? 1 : (1..n).inject(:*)
end
And, a final enhancement:
def factorial(n)
(1..n).inject(1, :*)
end
Supposing that n is a non-negative integer number, you can define a method to calculate the factorial:
def factorial(n)
tot = 1
(1..n).each do |n|
tot *= x
end
tot
end
Examples of its usage:
puts factorial(0) # 1
puts factorial(1) # 1
puts factorial(2) # 2
puts factorial(3) # 6
puts factorial(4) # 24
puts factorial(5) # 120
If you wan't to read the user input, call it like this:
puts 'Type the non-negative integer:'
n = gets.to_i
puts factorial(n)
class Factorial
attr_reader :num
def initialize(num)
#num = num
end
def find_factorial
(1..num).inject(:*) || 1
end
end
number = Factorial.new(8).find_factorial
puts number
Or you could just simply write:
(1..num).inject(:*) || 1
Try this too. Hope this helps anyone having the same problem in some way.
Method for finding the factorial of any number:
def factorial(number)
for i in 1...number do
number *= i
end
number
end
puts factorial(5)

Finding a prime number using a **custom** Ruby method

I would like to pass an array of numbers to my is_prime? method and return if the numbers are valid or not. I do not want to use:
require 'prime'
a = [1,2,3,4,5]
Hash[a.zip(a.map(&Prime.method(:prime?)))]
This is learning experience. My current code is only outputing the first number in the array. Can someone help me understand what I am doing wrong? Thanks!
def is_prime?(*nums)
i = 2
nums.each do |num|
while i < num
is_divisible = ((num % i) == 0)
if is_divisible == false
x = "#{num}: is NOT a prime number." #false
else
x = "#{num}: is a prime number." #true
end
i +=1
end
return x
end
end
puts is_prime?(27,13,42)
You are returning in the loop.
A few bugs in your method:
def is_prime?(*nums)
nums.each do |num|
return false if num == 1
next if num == 2 # 2 is the only even prime
i = 2 # needs to be reset for each num
while i < num
return false if num % i == 0 # num is not prime
i += 1
end
end
true # We'll reach here only if all the numbers are prime
end
This will return your results in the same format as your usage of the prime library with the same logic as your custom function:
def is_prime?(*nums)
nums.each_with_object({}) do |num, hsh|
hsh[num] = num > 1 && 2.upto(num - 1).none? { |i| num % i == 0 }
end
end
puts is_prime?(27,13,42)
# => {27=>false, 13=>true, 42=>false}
Since you mention this is just for learning, I'm assuming you know that a sieve is a better way to go for this than brute force iteration.
If you want an explanation of how the above code works or further help understanding why your current code doesn't, let me know in the comments.

more ruby way of doing project euler #2

I'm trying to learn Ruby, and am going through some of the Project Euler problems. I solved problem number two as such:
def fib(n)
return n if n < 2
vals = [0, 1]
n.times do
vals.push(vals[-1]+vals[-2])
end
return vals.last
end
i = 1
s = 0
while((v = fib(i)) < 4_000_000)
s+=v if v%2==0
i+=1
end
puts s
While that works, it seems not very ruby-ish—I couldn't come up with any good purely Ruby answer like I could with the first one ( puts (0..999).inject{ |sum, n| n%3==0||n%5==0 ? sum : sum+n }).
For a nice solution, why don't you create a Fibonacci number generator, like Prime or the Triangular example I gave here.
From this, you can use the nice Enumerable methods to handle the problem. You might want to wonder if there is any pattern to the even Fibonacci numbers too.
Edit your question to post your solution...
Note: there are more efficient ways than enumerating them, but they require more math, won't be as clear as this and would only shine if the 4 million was much higher.
As demas' has posted a solution, here's a cleaned up version:
class Fibo
class << self
include Enumerable
def each
return to_enum unless block_given?
a = 0; b = 1
loop do
a, b = b, a + b
yield a
end
end
end
end
puts Fibo.take_while { |i| i < 4000000 }.
select(&:even?).
inject(:+)
My version based on Marc-André Lafortune's answer:
class Some
#a = 1
#b = 2
class << self
include Enumerable
def each
1.upto(Float::INFINITY) do |i|
#a, #b = #b, #a + #b
yield #b
end
end
end
end
puts Some.take_while { |i| i < 4000000 }.select { |n| n%2 ==0 }
.inject(0) { |sum, item| sum + item } + 2
def fib
first, second, sum = 1,2,0
while second < 4000000
sum += second if second.even?
first, second = second, first + second
end
puts sum
end
You don't need return vals.last. You can just do vals.last, because Ruby will return the last expression (I think that's the correct term) by default.
fibs = [0,1]
begin
fibs.push(fibs[-1]+fibs[-2])
end while not fibs[-1]+fibs[-2]>4000000
puts fibs.inject{ |sum, n| n%2==0 ? sum+n : sum }
Here's what I got. I really don't see a need to wrap this in a class. You could in a larger program surely, but in a single small script I find that to just create additional instructions for the interpreter. You could select even, instead of rejecting odd but its pretty much the same thing.
fib = Enumerator.new do |y|
a = b = 1
loop do
y << a
a, b = b, a + b
end
end
puts fib.take_while{|i| i < 4000000}
.reject{|x| x.odd?}
.inject(:+)
That's my approach. I know it can be less lines of code, but maybe you can take something from it.
class Fib
def first
#p0 = 0
#p1 = 1
1
end
def next
r =
if #p1 == 1
2
else
#p0 + #p1
end
#p0 = #p1
#p1 = r
r
end
end
c = Fib.new
f = c.first
r = 0
while (f=c.next) < 4_000_000
r += f if f%2==0
end
puts r
I am new to Ruby, but here is the answer I came up with.
x=1
y=2
array = [1,2]
dar = []
begin
z = x + y
if z % 2 == 0
a = z
dar << a
end
x = y
y = z
array << z
end while z < 4000000
dar.inject {:+}
puts "#{dar.sum}"
def fib_nums(num)
array = [1, 2]
sum = 0
until array[-2] > num
array.push(array[-1] + array[-2])
end
array.each{|x| sum += x if x.even?}
sum
end

Resources