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
Related
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)
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
i tred creating a method called "Sum_plus_one" that accepts an array argument containing integers. Themethod should return the sum of the integers in the array after adding one to each of them.
example:
sum_plus_one([1,2,3])
result should be: 9
my code looks like this
def sum_plus_one(*nums)
for num in nums
num + 1
end
total = 0
for num in nums
total += num
end
return total
end
Why not do a little bit of math beforehand and see that summing the array-elements-plus-one is the same as summing the elements and then adding the array length? For example:
(5+1) + (6+1) + (11+1) = 5 + 6 + 11 + (1 + 1 + 1)
= 5 + 6 + 11 + 3
That gives you something nice and simple:
array.inject(:+) + array.length
map/reduce is handy here:
def sum_plus_one(nums)
nums.map(&:succ).reduce(:+)
end
Edit:
here is one way to make your code work:
def sum_plus_one(nums)
nums.map! do |num|
num + 1
end
total = 0
for num in nums
total += num
end
return total
end
Functional Style Version
[1, 2, 3].reduce(0) {|acc, n| acc + n + 1}
Use Enumerable#inject
[105] pry(main)> arr
=> [1, 2, 3]
[106] pry(main)> arr.inject(0) { |var, i| var + i + 1 }
=> 9
So the method would look like
def sum_plus_one(*nums)
nums.inject(0) { |var, num| var + num + 1 }
end
your problem is that you need to assign your num + 1 value to the corresponding element of the array that you are enumerating in the first loop.
maybe something like this:
for i in (0...nums.count)
nums[i] += 1
end
after that your program should work
(yes, you can use fancy libraries or constructs instead of the above loop)
please note that you can eliminate the top loop and just add num + 1 to your total in the second loop.
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.