How to write code for pyramid output in RUBY Language - ruby

I'm a new web developer and need assistance generating a given output to a problem:
def fib(n)
if (n<=2)
return 1
else
return (fib(n-1)+fib(n-2))
end
end
puts "Enter the number of terms:-"
n=gets.chomp.to_i
puts "The first #{n} terms of fibonnaci series are:-"
for c in 1..n
puts fib(c)
end
OUTPUT:
Enter the number of terms:-
5
The first 5 terms of fibonnaci series are:-
1
1
2
3
5
Excepted output:
1
22
333
55555
88888888
How would I be able to make my code produce the target output?

You just need to iterate through the range and calculate fibonacci for every member and you can multuply string with *
def fibonacci(n)
return n if (0..1).include?(n)
fibonacci(n - 1) + fibonacci(n - 2)
end
def print_pyramide(n)
(2..(n + 1)).each do |i|
fib = fibonacci(i)
puts fib.to_s * fib
end
end
print_pyramide(2)
# will print
# 1
# 22
print_pyramide(5)
# will print
# 1
# 22
# 333
# 55555
# 88888888

You could use Enumerator::produce, which made it's debut in Ruby v2.7.
Enumerator.produce([1, 1]) { |n1, n2| [n2, n1 + n2] }
.with_index(1)
.take(5)
.each { |(_,f),i| puts f.to_s * i }
prints
1
22
333
5555
88888
Note:
enum = Enumerator.produce([1, 1]) { |n1, n2| [n2, n1 + n2] }
#<Enumerator: #<Enumerator::Producer:0x00007fb18084de18>:each>
enum.next #=> [1, 1]
enum.next #=> [1, 2]
enum.next #=> [2, 3]
enum.next #=> [3, 5]
enum.next #=> [5, 8]

Related

#reduce loop within an #each loop isn't iterating through entire array

In the following program, the loop seems to stop after 2 runs, instead of 3 as expected. The expected value of sum_of_sums is 35, but here it is 23.
ary = [1,2,3,4]
sum_of_sums = 0
ary.each do # => [1, 2, 3, 4]
n=ary.shift # => 1, 2
sum_of_products = ary.reduce(0) do |memo,e| # => [2, 3, 4], [3, 4]
memo+(n*e) # => 2, 5, 9, 6, 14
end
sum_of_sums += sum_of_products # => 9, 23
end
sum_of_sums # => 23
It works as expected with [1,2,3]:
ary = [1,2,3]
sum_of_sums = 0
ary.each do # => [1, 2, 3]
n=ary.shift # => 1, 2
sum_of_products = ary.reduce(0) do |memo,e| # => [2, 3], [3]
memo+(n*e) # => 2, 5, 6
end
sum_of_sums += sum_of_products # => 5, 11
end
sum_of_sums # => 11
I'm trying to write a program which, for a set [a,b,c,d], computes
ab + ac + ad + bc + bd + cd. I don't know how to express this pattern other than by example. And yes I could probably do it more explicitly, or more easily by factoring out terms, but I want to know why this loop isn't working!
EDIT: Thanks folks... It seems the problem was that the array was being modified with #shift within the #each loop. I ended up succeeding with this:
ary = [1,2,3,4]
sum = 0
until ary.count==1 do
sum += ary.shift * ary.sum
end
sum
Considering that your question has been answered I would like to suggest a more efficient way to perform the calculation. Notice that
(a+b+c)**2 = a**2 + b**2 + c**2 + 2*(ab + ac + bc)
so
ab + ac + bc = ((a+b+c)**2 - (a**2 + b**2 + c**2))/2
We therefore may write
def sum_of_cross_terms(arr)
((arr.sum)**2 - arr.reduce(0) { |t,n| t + n**2 })/2
end
sum_of_cross_terms([1, 2, 3])
#=> 11
sum_of_cross_terms([1, 2, 3, 4])
#=> 35
We see that the computational complexity of this calculation is O(arr.size),
whereas the brute-force approach is O((arr.size)**2). An example of the latter is
def sum_of_cross_terms(arr)
arr.combination(2).sum { |a,b| a*b }
end
Like spickermann said your are modifying the array you are iterating while iterating it. This will produce unexpected results.
If you want to use shift then construct the loop using something which is not affected by shifting (modifying) the array.
(ary.size-1).times.map { ary.shift * ary.sum }.sum
Without modifying the array it becomes a bit more verbose:
(ary.size-1).times.map { |i| ary[i] * ary.drop(i+1).sum }.sum
You could also make a duplicate before iteration:
ary.dup.map { ary.shift * ary.sum }.sum
Or using with_index:
ary.map.with_index { |n, i| n * ary.drop(i+1).sum }.sum
There are many other ways to do this too, but hopefully this gives you some ideas.

Ruby Arrays - Find the sums of the diagonals

Haven't seen this one before, but I was wondering how you can find the sums of both diagonals of a 2D array in Ruby. Say you have a simple array, with 3 rows and 3 columns.
array = [1,2,3,4,5,6,7,8,9]
I can break it into groups of three by using
array.each_slice(3).to_a
Would now be
[1,2,3], [4,5,6], [7,8,9]
[1,2,3]
[4,5,6]
[7,8,9]
In this case, the diagonals are
1 + 5 + 9 = 15
3 + 5 + 7 = 15
So the total sum would be 15 + 15 = 30
I was thinking I could do something like
diagonal_sum = 0
for i in 0..2
for j in 0..2
diagonal_sum += array[i][j]
end
end
Here is my try :
array = [1,2,3,4,5,6,7,8,9]
sliced = array.each_slice(3).to_a
# As sliced size is 3, I took 2, i.e. 3 - 1
(0..2).map { |i| sliced[i][i] } #=> [1, 5, 9]
(0..2).map { |i| sliced[i][-i-1] } # => [3, 5, 7]
(0..2).map { |i| sliced[i][i] }.reduce :+
# => 15
(0..2).map { |i| sliced[i][-i-1] }.reduce :+
# => 15
As per the above observation it seems in one iteration you can do solve :
left_diagonal, right_diagoal = (0..2).each_with_object([[], []]) do |i, a|
a[0] << sliced[i][i]
a[1] << sliced[i][-i-1]
end
left_diagonal.reduce(:+) # => 15
right_diagonal.reduce(:+) # => 15
Added, OOP style of code :
class SquareMatrix
attr_reader :array, :order
def initialize array, n
#array = array.each_slice(n).to_a
#order = n
end
def collect_both_diagonal_elements
(0...order).collect_concat { |i| [ array[i][i], array[i][-i-1] ] }
end
def collect_left_diagonal_elements
(0...order).collect { |i| array[i][i] }
end
def collect_right_diagonal_elements
(0...order).collect { |i| array[i][-i-1] }
end
def sum_of_diagonal_elements type
case type
when :all then collect_both_diagonal_elements.reduce(0, :+)
when :right then collect_right_diagonal_elements.reduce(0, :+)
when :left then collect_left_diagonal_elements.reduce(0, :+)
end
end
end
array = [1,2,3,4,5,6,7,8,9]
sqm = SquareMatrix.new array, 3
sqm.collect_both_diagonal_elements # => [1, 3, 5, 5, 9, 7]
sqm.sum_of_diagonal_elements :all # => 30
sqm.collect_left_diagonal_elements # => [1, 5, 9]
sqm.sum_of_diagonal_elements :left # => 15
sqm.collect_right_diagonal_elements # => [3, 5, 7]
sqm.sum_of_diagonal_elements :right # => 15
The following is mostly for the academic discussion:
For the main diagonal, you are looking for the "Trace" function which is defined for the "Matrix" class. So the following will work (although it doesn't get you the other diagonal and I wouldn't bet on its efficiency):
require 'Matrix'
a = array.each_slice(3).to_a
Matrix[*a].trace
To get the other diagonal you have to somehow "flip" the matrix, so the following seems to work (Since the result of each_slice is an array of rows, reverse reverses the order of the row. Reversing the order of the columns is more difficult):
Matrix[*a.reverse].trace
I totally forgot about #map.with_index ...Thanks to #xlembouras , heres a one-liner
first_diagonal = array.map.with_index {|row, i| row[i]} .inject :+
inverted_diagonal = array.map.with_index {|row, i| row[-i-1]} .inject :+
It's possible to make it a one-liner:
first_diagonal, inverted_diagonal = (array.map.with_index {|row, i| row[i]} .inject :+) , (array.map.with_index {|row, i| row[-i-1]} .inject :+)
Original:
Here's a thought, which makes me think it would be great to have a #map_with_index method:
for a first to last diagonal:
i = -1
array.map { |row| row[i=i+1] }.inject :+
for the last to first diagonal (assuming a square array):
i = array.length
array.map { |row| row[i=i-1] }.inject :+
a = [1,2,3,4,5,6,7,8,9]
p a.values_at(0,2,4,4,6,8).inject(&:+) #=> 30
I would try iterating through the array and keep the values that I need according to the length of the (grouped) array
array = [[1,2,3], [4,5,6], [7,8,9]]
dimension = array.length
array.flatten.map.with_index do |x,i|
x if [0, dimension - 1].include?(i % dimension)
end.compact.inject(:+)
#=> 30
You don't need to first apply slice:
arr = [1,2,3,4,5,6,7,8,9]
We visualize arr as:
1 2 3
4 5 6
7 8 9
n = Math.sqrt(arr.size).round
#=> 3
For the main diagonal:
(0...arr.size).step(n+1).reduce(0) { |t,i| t+arr[i] }
#=> 15
For the off-diagonal:
(n-1..arr.size-n).step(n-1).reduce(0) { |t,i| t+arr[i] }
#=> 15
Another example:
arr = [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]
1 2 3 4
5 6 7 8
9 0 1 2
3 4 5 6
n = Math.sqrt(arr.size).round
#=> 4
(0...arr.size).step(n+1).reduce(0) { |t,i| t+arr[i] } +
(n-1..arr.size-n).step(n-1).reduce(0) { |t,i| t+arr[i] }
#=> 14 + 14 => 28
require 'Matrix'
arr = [[1, 3, 4], [2, 5, 7], [6, 7, 8]]
diag1 = Matrix[*arr].tr
diag2 = Matrix[*arr.reverse].tr
def diagonal(array)
single=array.flatten
new=[]
i=array.length-1
while i < single.length-2
new << single[i]
i+=array.length-1
end
new.sum
end
p diagonal([
[1, 2, 3],
[4, 5, 6],
[7, 9, 8],
])
OUTPUT
15
That is for finding the sum of right diagonal of a 2D array

Distributions using nested loops

I would like to write a program which generates all distributions for a given n.
For example, if I enter n equal to 7, the returned result will be:
7
6 1
5 2
5 1 1
4 3
4 2 1
4 1 1 1
3 3 1
3 2 2
3 2 1 1
3 1 1 1 1
2 2 2 1
2 2 1 1 1
2 1 1 1 1 1
1 1 1 1 1 1 1
I wrote the following code:
def sum(a, n)
for i in 1..a.length
a.each do |a|
z = a+i
if z == n
print i
puts a
end
end
end
end
def distribution(n)
numbers_container = []
for i in 1..n-1
numbers_container<<i
end
sum(numbers_container,n)
end
puts "Enter n"
n = gets.chomp.to_i
distribution(n)
I'm stuck in the part where the program needs to check the sum for more than two augends. I don't have an idea how can I write a second loop.
I suggest you use recursion.
Code
def all_the_sums(n, mx=n, p=[])
return [p] if n.zero?
mx.downto(1).each_with_object([]) { |i,a|
a.concat(all_the_sums(n-i, [n-i,i].min, p + [i])) }
end
Example
all_the_sums(7)
#=> [[7],
# [6, 1],
# [5, 2], [5, 1, 1],
# [4, 3], [4, 2, 1], [4, 1, 1, 1],
# [3, 3, 1], [3, 2, 2], [3, 2, 1, 1], [3, 1, 1, 1, 1],
# [2, 2, 2, 1], [2, 2, 1, 1, 1], [2, 1, 1, 1, 1, 1],
# [1, 1, 1, 1, 1, 1, 1]]
Explanation
The argument mx is to avoid the generation of permuations of results. For example, one sequence is [4,2,1]. There are six permutations of the elements of this array (e.g., [4,1,2], [2,4,1] and so on), but we want just one.
Now consider the calculations performed by:
all_the_sums(3)
Each eight-space indentation below reflects a recursive call to the method.
We begin with
n = 3
mx = 3
p = []
return [[]] if 3.zero? #=> no return
# first value passed block by 3.downto(1)..
i = 3
a = []
# invoke all_the_sums(0, [0,3].min, []+[3])
all_the_sums(0, 0, [3])
return [[3]] if 0.zero? #=> return [[3]]
a.concat([[3]]) #=> [].concat([[3]]) => [[3]]
# second value passed block by 3.downto(1)..
i = 2
a = [[3]]
# invoke all_the_sums(1, [1,2].min, []+[2])
all_the_sums(1, 1, [2])
return [[2]] if 1.zero? #=> do not return
# first and only value passed block by 1.downto(1)..
i = 1
a = []
# invoke all_the_sums(0, [0,1].min, [2]+[1])
all_the_sums(0, 0, [2,1])
return [[2,1]] if 0.zero? #=> [[2,1]] returned
a.concat([[2,1]]) #=> [].concat([[2,1]]) => [[2,1]]
return a #=> [[2,1]]
a.concat([[2,1]]) #=> [[3]].concat([[2,1]]) => [[3],[2,1]]
# third and last value passed block by 3.downto(1)..
i = 1
a = [[3],[2,1]]
# invoke all_the_sums(2, [2,1].min, [1])
all_the_sums(2, 1, [1])
return [] if 2.zero? #=> [] not returned
# first and only value passed block by 1.downto(1)..
i = 1
a = []
# invoke all_the_sums(1, [1,1].min, [1]+[1])
all_the_sums(1, 1, [1,1])
return [1,1] if 1.zero? #=> [1,1] not returned
# first and only value passed block by 1.downto(1)..
i = 1
a = []
# invoke all_the_sums(0, [0,1].min, [1,1]+[1]])
all_the_sums(0, 0, [1,1,1])
return [1,1,1] if 1.zero?
#=> return [1,1,1]
a.concat([[1,1,1]]) #=> [[1,1,1]]
return a #=> [[1,1,1]]
a.concat([[1,1,1]]) #=> [].concat([[1,1,1]]) => [[1,1,1]]
return a #=> [[1,1,1]]
a.concat([[1,1,1]]) #=> [[3],[2,1]].concat([[1,1,1]])
return a #=> [[3],[2,1],[1,1,1]]
You can use unary with parameters to have infinite amounts of parameters:
def test_method *parameters
puts parameters
puts parameters.class
end
test_method("a", "b", "c", "d")
So, parameters inside the block becomes an array of parameters. You can then easly loop through them:
parameters.each { |par| p par }
Also, don't use for loops for this as they are less readable than using each methods.
[1..n-1].each do i
# body omitted
end
I think you be able to work it out if you tried to call sum recursively. After this bit:
print i
puts a
Try calling sum again, like this:
sum((1..a).to_a, a)
It won't solve it, but it might lead you in the right direction.

Pulling indexes from an array and variable scope

I'm running through TestFirstRuby and I've been stuck on problem 12, building a Reverse Polish Notation calculator. I've gotten through all of the tests except for the last one, asking me to take a string ("1 2 3 * +" and then "1 2 3 * + 4 5 / -"), and then evaluate the expression.
What I'm trying to do is convert the string to an array, changing the numbers into integers and the operators into symbols, then go through the array and evaluate the expression anytime it comes to an operator.
Here's the relevant part of the code:
def initialize
#expression = ''
end
def tokens(string)
tokens = string.split(' ')
tokens.map! { |digit| /[0-9]/.match(digit) ? digit.to_i : digit.to_sym }
end
def evaluate(string)
#1 2 3 * +
#1 2 3 * + 4 5 - /
total = 0
#expression = tokens(string)
#expression.map!{|item|
index = #expression.index(item)
if item == :+
total = total + (#expression[index-1] + #expression[index-2])
2.times {#expression.delete_at(index-1)}
elsif item == :-
total = total + (#expression[index-1] - #expression[index-2])
2.times {#expression.delete_at(index-1)}
elsif item == :x
total = total + (#expression[index-1] * #expression[index-2])
2.times {#expression.delete_at(index-1)}
elsif item == :/
total = total + (#expression[index-1].to_f / #expression[index-2])
2.times {#expression.delete_at(index-1)}
end
}
total
end
What I WANT to happen is this: for each item in the array, it checks if it matches any of the symbols. If there's a match, it changes the element two spaces back from the symbol into the value of whatever the expression is (so 2 3 * becomes 5 3 *). Then, I"m trying to delete the operator and the integer immediately before it, leaving only the evaluated value. I'm doing this by running delete_at twice on the index just before the operator (ideally, 5 3 * goes to 5 * and then just 5). Then it'll move on to the next element in the array.
What I THINK is going wrong, and am having trouble fixing: I think something's going on with the variable scope here. I'm trying to get the expression to be permanently changed every time it runs the code on whatever element it's currently on in the each loop. For each element, a variable 'index' is set using #expression.index(item). This should reset for each element in the each loop. I THINK what's going on is that the original #expression array is being called on for each iteration of the each loop, unchanged from each iteration of the each loop.
The error I'm getting is saying that when it gets to the '+' at the end of the first test string ('1 2 3 * +'), it's trying to add using :x, meaning that when it's calling for the two variables to add together (#expression[index-1] + #expression[index-2]), it's pulling the symbol, which I thought should have been deleted from #expression already. So what I'm hoping will evaluate as 6 + 1 is being evaluated as 3 + :x, which wouldn't work. It's pulling elements from the original array, instead of pulling from the array as it's changed.
Hopefully I'm explaining this clearly enough. Any advice would be great. I'm thinking there's something with scope going on, but I can't find anything specific to this kind of problem to help me out. I've tried different ways of coding this (.map, .each_with_index, .map.with_index, and others), and I'm getting the same problem each time.
You have a tremendous amount of redundant code. In particular, you replicate the operations for each of the four operators. Here is a more Ruby-like way of implementing your calculator.
Code
def evaluate(string)
arr = create_arr(string)
until arr.size == 1
i = arr.index(arr.find { |e| e.is_a? Symbol })
arr[i-2] = arr[i-2].send(arr[i], arr[i-1])
arr.delete_at(i)
arr.delete_at(i-1)
end
arr.first
end
def create_arr(string)
string.split(/\s+/).map { |e| e =~ /-?[0-9]+/ ? e.to_i : e.to_sym }
end
The line in create_arr could alternatively end : e } (sent accepts a string or symbol for the method), in which case e.is_a? Symbol would be changed to e.is_a? String.
Examples
evaluate("3 4 * 2 / 3 - 2 *") #=> 6
evaluate("10 2 / 3 + 2 / 2 -") #=> 2
evaluate("8 -2 / 1 +") #=> -3
evaluate("5 1 2 + 4 * + 3 -") #=> 14
Explanation
Suppose
string = "2 3 4 * 2 / +"
Step 1
arr = create_arr(string) #=> [2, 3, 4, :*, 2, :/, :+]
arr.size == 1 #=> false
v = arr.find { |e| e.is_a? Symbol } #=> :*
i = arr.index(v) #=> 3
arr[i-2] = arr[i-2].send(arr[i], arr[i-1])
# arr[1] = arr[1].send(arr[3], arr[2])
# arr[1] = 3.send(:*, 4) #=> 12
arr #=> [2, 12, 4, :*, 2, :/, :+]
arr.delete_at(i) #=> :*
arr #=> [2, 12, 4, 2, :/, :+]
arr.delete_at(i-1) #=> 4
arr #=> [2, 12, 2, :/, :+]
Step 2
arr.size == 1 #=> false
v = arr.find { |e| e.is_a? Symbol } #=> :/
i = arr.index(v) #=> 3
arr[i-2] = arr[i-2].send(arr[i], arr[i-1])
# arr[1] = arr[1].send(arr[3], arr[2])
# arr[1] = 12.send(:/, 2) #=> 6
arr #=> [2, 6, 2, :/, :+]
arr.delete_at(i) #=> :/
arr #=> [2, 6, 2, :+]
arr.delete_at(i-1) #=> 2
arr #=> [2, 6, :+]
Step 3
arr.size == 1 #=> false
v = arr.find { |e| e.is_a? Symbol } #=> :+
i = arr.index(v) #=> 2
arr[i-2] = arr[i-2].send(arr[i], arr[i-1])
# arr[0] = arr[0].send(arr[2], arr[1])
# arr[0] = 2.send(:+, 6) #=> 8
arr #=> [8, 6, :+]
arr.delete_at(i) #=> :+
arr #=> [8, 6]
arr.delete_at(i-1) #=> 6
arr #=> [8]
Step 4
arr.size == 1 #=> true
arr.first #=> 8

Random permutation iterator

Need to augment Enumerable module with new iterator, that returns elements of collection in random order. The only information about collection - it responds to each. No other assumptions about elements.
I have a solution - to wrap elements into Array and then use sample method:
def each_permuted
tmp = []
self.each do |w|
tmp << w
end
tmp.sample(tmp.length).each do |w|
yield w
end
end
Don't like it, because here we go through collection twice(even three times counting tmp.sample random permutation).
Is it possible with single go through?
I doubt that it is possible to do with signle go through. Take a look at this page: http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_.22inside-out.22_algorithm
I implemented the algorithm named "the inside-out algorithm" in the article (it goes through collection twice):
def each_permuted
generator = Random.new
tmp = []
self.each do |w|
r = generator.rand(tmp.size + 1)
if r == tmp.size
tmp << w
else
tmp << tmp[r]
tmp[r] = w
end
end
tmp.each do |w|
yield w
end
end
Tests:
1.9.3p327 :064 > [1,2,3,4,5,6].each_permuted { |x| p x }
1
5
2
6
3
4
=> [1, 5, 2, 6, 3, 4]
1.9.3p327 :065 > [1,2,3,4,5,6].each_permuted { |x| p x }
4
3
2
5
6
1
=> [4, 3, 2, 5, 6, 1]
1.9.3p327 :066 > [1,2,3,4,5,6].each_permuted { |x| p x }
4
5
2
1
3
6
=> [4, 5, 2, 1, 3, 6]
def each_permuted &pr; shuffle.each(&pr) end

Resources