Why is the output the same?
First inject:
puts (3...10).inject(0) { |sum, x| (x % 3 == 0 || x % 5 == 0) ? sum + x : sum }
# => 23
Second inject:
puts (3...10).inject { |sum, x| (x % 3 == 0 || x % 5 == 0) ? sum + x : sum }
# => 23
# Why not 26?
I thought if there is no argument passed to it, inject uses the first element of the collection as initial value.
So the second inject should return the same value as this one:
puts (3...10).inject(3) { |sum, x| (x % 3 == 0 || x % 5 == 0) ? sum + x : sum }
# => 26
Why does these two injects give the same output in ruby?
... Because they're supposed to. They only differ by the addition of a 0.
I thought if there is no argument passed to it, inject uses the first element of the collection as initial value.
It does. But it doesn't duplicate it.
Your first example receives these numbers:
0, 3, 4, 5, 6, 7, 8, 9
Your second example receives these numbers:
3, 4, 5, 6, ...
Adding 0 to the beginning doesn't affect the result, they're both 23, not 26 as you claim.
Your 3rd example returns 26 because it receives these numbers:
3, 3, 4, 5, 6, ...
#inject() with an argument:
result = (3...10).inject(0) do |sum, x|
puts "#{sum} <-- #{x}: sum = #{sum+x}"
sum + x
end
--output:--
0 <-- 3: sum = 3
3 <-- 4: sum = 7
7 <-- 5: sum = 12
12 <-- 6: sum = 18
18 <-- 7: sum = 25
25 <-- 8: sum = 33
33 <-- 9: sum = 42
...
#inject without an argument:
result = (3...10).inject() do |sum, x|
puts "#{sum} <-- #{x}: sum = #{sum+x}"
sum + x
end
--output:--
3 <-- 4: sum = 7
7 <-- 5: sum = 12
12 <-- 6: sum = 18
18 <-- 7: sum = 25
25 <-- 8: sum = 33
33 <-- 9: sum = 42
I always thought it takes the first element of the collection as
initial value and still performs the first iteration
The first iteration uses arr[0] as the sum and arr[1] as the first x. When you don't provide an argument for inject(), it's equivalent to doing this:
data = (3...10).to_a
initial_sum = data.shift
data.inject(initial_sum) do |sum, x|
puts "#{sum} <-- #{x}: sum = #{sum+x}"
sum + x
end
--output:--
3 <-- 4: sum = 7
7 <-- 5: sum = 12
12 <-- 6: sum = 18
18 <-- 7: sum = 25
25 <-- 8: sum = 33
33 <-- 9: sum = 42
Related
I'm trying to create a method that takes a number and then puts every number between that and 0 as an exponent to the number 2.
2^0 = 1
2^1 = 2
2^2 = 4
2^3 = 8
2^4 = 16
This is as far as I've gotten. . .
def powers_of_two(n)
n.map { |x| 2 ** (0..x) }
end
I believe I'm not far off in my attempt.
For example, like this:
def power_of_two(n) = (0..n).each { puts 2 ** _1 }
power_of_two(4)
#=> 1
2
4
8
16
You can build an enumerator that generates the numbers via Enumerator.produce:
powers = Enumerator.produce(1) { |i| i * 2 }
powers.take(5)
#=>[1, 2, 4, 8, 16]
The block generates each number based on the previous one, starting at 1.
The same works for bit-shifting:
powers = Enumerator.produce(1) { |i| i << 1 }
powers.take(5)
#=>[1, 2, 4, 8, 16]
As we are dealing with powers of 2, try this bit-shifting method. (I assume the given number n is non-negative.)
def po2(n)
(0..n).each { |i| puts 1 << i }
end
po2(7)
1
2
4
8
16
32
64
128
See Integer#<< and possibly this tutorial.
One could alternatively create a proc.
po2 = Proc.new { |n| (0..n).each { |i| puts 1 << i } }
#=> #<Proc:0x00007f91a5222bb0 <main>:0>
po2(7)
1
2
4
8
16
32
64
128
Newbie here! Trying to implement a program to print the first 20 Fibonacci numbers in Ruby. I've managed to create a program which generates the nth number, but I want to produce all from 0 through to 20.
Is there a simple way to do this or do I need to rewrite the whole program?
CURRENT CODE
def fib(n)
if n < 1
return 0
elsif n == 1
return 1
else fib(n-2) + fib(n-1)
end
end
puts fib(20)
CURRENT OUTPUT EXAMPLE
6765
DESIRED OUTCOME
0
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
At the moment you only print the last value returned by your method (fib(20)) but not the result of all intermediate steps.
An easy way would be to cache all intermediate results in a hash data structure. This would also improve performance for big n because you do not need to recalculate many values over and over again.
Then you can just print out all results from 0 to n:
def cached_fib(n)
#cache ||= Hash.new do |cache, n|
#cache[n] = n < 2 ? n : cache[n-1] + cache[n-2]
end
#cache[n]
end
def fib(n)
0.upto(n) { |i| puts cached_fib(i) }
end
fib(20)
#=> 0
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
Printing each value is easier with a button-up approach where you start at 0 and 1 and calculate each following value based on its predecessors, e.g.:
i, j = 0, 1
puts i
puts j
21.times do
k = i + j
puts k
i, j = j, k
end
You could turn the above into an Enumerator:
fib = Enumerator.new do |y|
i, j = 0, 1
y << i
y << j
loop do
k = i + j
y << k
i, j = j, k
end
end
Which will generate the sequence:
fib.take(21)
#=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144,
# 233, 377, 610, 987, 1597, 2584, 4181, 6765]
I have this method which switches the number digit 5 with 7.
def switch_digit(num)
if num <= 0
return 0
end
digit = num % 10
if (digit == 5)
digit = 7
end
return switch_digit(num/10) * 10 + digit
end
switch_digit(5952)
Can someone explain why once the method hits the base case it doesn't return 0?
How does this recursive method actually work? Does it append the returned digit with the next digit?
I added a little change to your code, to be aware it's working.
Finally I also expected the value of the method was 0, but it is not.
The end is reached, but the returned value is not 0. Why?
def switch_digit(num, array)
if num <= 0
array << num
p array
puts "The end"
return 0
end
digit = num % 10
array << [digit, num]
if (digit == 5)
digit = 7
end
return p switch_digit(num/10, array) * 10 + digit
end
p "returned value = " + switch_digit(123456789, Array.new).to_s
Which outputs:
#=> [[9, 123456789], [8, 12345678], [7, 1234567], [6, 123456], [5, 12345], [4, 1234], [3, 123], [2, 12], [1, 1], 0]
#=> The end
#=> 1
#=> 12
#=> 123
#=> 1234
#=> 12347
#=> 123476
#=> 1234767
#=> 12347678
#=> 123476789
#=> "returned value = 123476789"
The base case returns 0, but the overall result is determined by the return switch_digit(num/10) * 10 + digit
Follow the code through with a smaller example e.g. switch_digit(15):
num <= 0 # no
digit = num % 10 # 5
digit == 5 # yep, so swap it for a 7
return switch_digit(num/10) * 10 + 7
num/10 is 1 so what does the recursive switch_digit(1) evaluate to?
num <= 0 # no
digit = num % 10 # 1
digit == 1 # so leave it unchanged
return switch_digit(num/10) * 10 + 1
num/10 is 0 so now we hit the base case
switch_digit(15) == switch_digit(1) * 10 + 7
switch_digit(1) == switch_digit(0) * 10 + 1
switch_digit(0) == 0 # the base case
working back up, plugging in values from lower down results:
switch_digit(1) == 0 * 10 + 1 == 1
switch_digit(15) == 1 * 10 + 7 == 17
I'd also add that there's nothing specific to Ruby about how recursion is handled here. Any other descriptions of recursion, or classic example such as a recursive factorial function should help you get a better understanding.
I need to improve the performance of this algorithm. I believe the answer lies in the application of the pisano period.
This algorithm must return the last digit of the sum of fib numbers from f(m) to f(n).
Here is what I have so far:
def fib(n)
a = []
a << 0 << 1
(n+1).times do |i|
a << a[-1] + a[-2]
end
a[n]
end
def fib_partial_sum(m, n)
if n == m
fib(m) % 10
else
m = fib(m + 1) - 1
n = fib(n + 2) - 1
(n - m) % 10
end
end
if __FILE__ == $0
m, n = gets.split().map(&:to_i)
puts "#{fib_partial_sum(m, n)}"
end
The last digit of any fib num repeats every 60 numbers. Therefore, we can do this, n, m = n % 60, m % 60. An improvement, but not quite there yet, fails on input 567717153638 567717153638):
def fib(n)
a = []
a << 0 << 1
(n+1).times do |i|
a << a[-1] + a[-2]
end
a[n]
end
def fib_partial_sum(m, n)
if n == m
fib(m)
else
m = m % 60
n = n % 60
m = fib(m + 1) - 1
n = fib(n + 2) - 1
(n - m) % 10
end
end
if __FILE__ == $0
m, n = gets.split().map(&:to_i)
puts "#{fib_partial_sum(m, n)}"
end
Here is a nice solution to the problem, it passes all time and memory constraints.
This way you never have to calculate a fib num greater that f(60). It can handle very large inputs efficiently.
def fib(n)
a, b = 0, 1
(n-1).times do
a, b = b, (a + b) % 10
end
b
end
def fib_partial_sum(m, n)
if n == m
fib(m % 60)
else
m = m % 60
n = n % 60
m = fib(m + 1) - 1
n = fib(n + 2) - 1
(n - m) % 10
end
end
if __FILE__ == $0
m, n = gets.split().map(&:to_i)
puts "#{fib_partial_sum(m, n)}"
end
(Max time used: 0.05/5.00, max memory used: 8699904/536870912.)
The following requires only a single pass of the numbers between zero and at most [n,m+60].min, where m..n is the range of interest, and has a minimal memory requirement. It makes use of #nloveladyallen's observation that the last digit of Fibonacci numbers has a periodicity of 60.
Code
def fib_last(m,n)
n -= 60*((n-m)/60)
fib_sum(m,n) % 10
end
def fib_sum(m,n)
return nil if m < 0 || m > n
return n if n < 2
next_to_last, last = fib(m-1)
(m..n).reduce(0) do |tot,_|
current = next_to_last + last
next_to_last = last
last = current
tot + current
end
end
def fib(m)
next_to_last, last = -1, 1
0.upto(m).each do |n|
current = next_to_last + last
next_to_last, last = last, current
end
[next_to_last, last]
end
Example
m, n = 6, 12
(n+1).times { |i| puts "#{i}: #{fib(i)}" }
0: [0, 0]
1: [0, 1]
2: [1, 1]
3: [1, 2]
4: [2, 3]
5: [3, 5]
6: [5, 8]
7: [8, 13]
8: [13, 21]
9: [21, 34]
10: [34, 55]
11: [55, 89]
12: [89, 144]
fib_last(6,12) #=> 4 (fib_sum(6,12) #=> 8 + 13 + 21 + 34 + 55 + 89 + 144 = 364)
fib_last(1,2) #=> 2 (fib_sum(1,2) #=> 1 + 1 = 2)
fib_last(1,3) #=> 4 (fib_sum(1,3) #=> 1 + 1 + 2 = 4)
fib_last(1,4) #=> 7 (fib_sum(1,4) #=> 1 + 1 + 2 + 3 = 7)
fib_last(2,3) #=> 3 (fib_sum(2,3) #=> 1 + 2 = 3)
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
a = [1,2]
upto = 4_000_000
while a[-2] + a[-1] < upto
a << a[-2] + a[-1]
end
sum = 0
a.each { |x| sum += x if x.even? }
puts "The result is #{sum}"
How does this work? What is a[-2]? What does that even mean? The negative second index of a or a minus 2? Thanks for the explanation.
This is negative index. a[-1] and a[-2] are the last two elements of the array a.
If you watch closely, you'll see the following sequence:
1 1 2 3 5 8 13 21 34 55 89 144 ...
The formula for mapping the Fibonacci sequence is:
And you only want the sum of the even numbers such as:
1 1 2 3 5 8 13 21 34 55 89 144 ...
So you can map a new formula such as:
And you will obtain the following sequence:
2 8 34 144 ...
Code example (Go):
package main
import "fmt"
func fibonacci() func() int {
first, second := 0, 2
return func() int {
ret := first
first, second = second, first+(4*second)
return ret
}
}
func main() {
sum := 0
f := fibonacci()
for i := 0; sum < 4000000; i++ {
sum += f()
}
fmt.Println(sum)
}
In that case you will not need the if conditionals.
Hope that helped you! Cheers!
def fibonacci(array)
new_fibs = []
new_fibs << array[0]
new_fibs << array[1]
sum = 0
i = 0
while new_fibs.last < 4_000_000
sum = new_fibs[i] + new_fibs[i+1]
new_fibs << sum
i += 1
end
total_even = 0
new_fibs.each do |fibs|
if fibs%2 == 0
total_even = total_even + fibs
end
end
p total_even
end
fibonacci([1,2])
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.