Related
HackerRank Diagonal Difference Problem.
Print the absolute difference between the sums of the matrix's two diagonals as a single integer.
Link to problem: https://www.hackerrank.com/challenges/diagonal-difference/problem
I have been trying for hours to solve this problem in Ruby. I happened upon an answer that someone else figured out.
I am now please asking for help in understanding how this method works. I want to understand what it is doing. I am confused by the entirety of the loop.
a.each_with_index do |array, index|
left_right += array[index]
right_left += array[-index-1]
Could someone please explain step-by-step what is happening in this block of code so I can learn and better understand Ruby? Thank you.
def diagonalDifference(a)
left_right=0
right_left=0
a.each_with_index do |array, index|
left_right += array[index]
right_left += array[-index-1]
end
v = right_left - left_right
return v.abs
end
The main skew diagonal (or main secondary diagonal) of a nxn matrix a is comprised of the elements a[n-1][0], a[n-2][1],..., a[1][n-2], a[0][n-1]].
Part of the problem is that the variables have not been given descriptive names. I would write that as follows.
def diagonal_difference(arr)
main_diagonal_sum=0
main_skew_diagonal_sum=0
arr.each_with_index do |row, i|
main_diagonal_sum += row[i]
main_skew_diagonal_sum += row[-i-1]
end
(main_diagonal_sum - main_skew_diagonal_sum).abs
end
I expect row[-i-1] might be the most confusing part of the code. Suppose i = 0, then row[-0-1] #=> row[-1], which is the last element of row. When i = 1, row[-1-1] #=> row[-2], which is the next-to-last element of row, and so on. That could instead be written row[row.size-i-1].
Note return is not needed if, as here, the return value of the last statement executed (before the method returns) is to be returned by the method.
Let's add some puts statements in the method and work through an example.
def diagonal_difference(arr)
puts "arr=#{arr}"
main_diagonal_sum=0
main_skew_diagonal_sum=0
arr.each_with_index do |row, i|
puts "row=#{row}, i=#{i}"
main_diagonal_sum += row[i]
puts " row[#{i}]=#{row[i]}, main_diagonal_sum=#{main_diagonal_sum}"
main_skew_diagonal_sum += row[-i-1]
puts " row[-#{i}-1]=#{row[-i-1]}, main_skew_diagonal_sum=#{main_skew_diagonal_sum}"
end
(main_diagonal_sum - main_skew_diagonal_sum).abs
end
arr = [[1,2,3],
[4,5,6],
[9,8,7]]
The main diagonal sum is 1+5+7 #=> 13 and the main skew diagonal sum is 3+5+9 #=> 17, so we expect the method to return (13-17).abs #=> 4.
diagonal_difference(arr)
#=> 4
prints the following.
arr=[[1, 2, 3], [4, 5, 6], [9, 8, 7]]
row=[1, 2, 3], i=0
row[0]=1, main_diagonal_sum=1
row[-0-1]=3, main_skew_diagonal_sum=3
row=[4, 5, 6], i=1
row[1]=5, main_diagonal_sum=6
row[-1-1]=5, main_skew_diagonal_sum=8
row=[9, 8, 7], i=2
row[2]=7, main_diagonal_sum=13
row[-2-1]=9, main_skew_diagonal_sum=17
This can alternatively be written as follows. We first need a helper method to rotate a square array 90 degrees.
def rotate90(arr)
arr.map(&:reverse).transpose
end
arr = [[1,2,3],
[4,5,6],
[9,8,7]]
arr90 = rotate90(arr)
#=> [[3, 6, 7],
# [2, 5, 8],
# [1, 4, 9]]
Next, I'll add a second helper to sum the main diagonal of a square matrix. That's easiest by using Matrix#trace.
require 'matrix'
def trace(arr)
Matrix[*arr].trace
end
We therefore may write the following.
(trace(arr90) - trace(arr)).abs
#=> (17 - 13).abs => 4.abs => 4
See following
11 2 4
4 5 6
10 8 -12
So, a = [ [11, 2, 4], [4, 5, 6], [10, 8, -12] ]
Now ref each_with_index method for a.each_with_index do |array, index|. during first iteration array will be [11, 2, 4] & index will be 0. array[0] = 11 & array[-0-1] i.e. array[-1] = 4
Similarly for second iteration array[1] = 5 & array[-1-1] i.e. array[-2] = 5& so on.
You'll get
2.3.1 :360 > left_right # 11 + 5 - 12
=> 4
2.3.1 :361 > right_left # 4 + 5 + 10
=> 19
2.3.1 :362 > v = right_left - left_right
=> 15
v.abs is used to return absolute difference in case v is negative, Ref abs method of Numeric class.
Note:- return keyword is optional if it is the last non comment line in a method.
You can use the Matrix library as proposed in this answer.
require 'matrix'
(Matrix[*arr].tr - Matrix[*arr.reverse].tr).abs
Where arr is an array of depth 2 with length n and each sub-array is also of length n e.g. [[a,b],[c,d]].
Sidenote: NB I am posting this as an answer, not a comment, for the sake of formatting; it should not be upvoted.
The more ruby idiomatic version of the snippet you have posted would be:
def diagonal_difference(a)
a.each.with_object([0, 0]).with_index do |(e, left_right), idx|
left_right[0] += array[idx]
right_left[1] += array[-idx-1]
end.reduce(:-).abs
end
I am solving the pyramid problem, in which an array is reduced to a single element over time by subtracting two consecutive numbers in each iteration.
input: [1, 5, 9, 2, 3, 5, 6]
iterations
[4, 4, -7, 1, 2, 1],
[0, -11, 8, 1, -1],
[-11, 19, -7, -2],
[30, -26, 5],
[-56, 31],
[87]
output: 87
What is the best way or ruby way to solve this problem? This can be done by inheriting array and making a new class, but I don't know how. Please help. I write this code to solve it:
a = [1,5,9,2,3,5,6]
class Array
def pyr
a = self.each_cons(2).to_a.map! { |e| e[1] - e[0] }
a
end
end
while a.length > 1
a = a.pyr
ans = a[0]
end
p ans
I see three ways to approach this.
Reopen the Array class
Sure, if in your particular ruby script/project this is an elementary functionality of an array, reopen the class. But if you are going to re-open a class, at least make sure the name is something meaningful. pyr? Why not write a full name, so no conflicts are possible, something like next_pyramid_iteration (I have never heard of this pyramid problem, so excuse me if I am way of base here).
Make a class inherit from Array
class Pyramid < Array
def next_iteration
self.each_const(2).map! { |e| e[1] - e[o] }
end
end
and then your calculation would become something like
pyramid = Pyramid.new([1,5,9,2,3,5,6])
while pyramid.length > 1
pyramid.next_iteration
end
pyramid[0]
Make a specific class to do the calculation
I am not quite sure what you are trying to achieve, but why not just make a specific class that knows how to calculate pyramids?
class PyramidCalculator
def initialize(arr)
#pyramid = arr
end
def calculate
while #pyramid.length > 1
do_next_iteration
end
#pyramid.first
end
def self.calculate(arr)
PyramidCalculator.new(arr).calculate
end
protected
def do_next_iteration
#pyramid = #pyramid.each_const(2).map! { |e| e[1] - e[o] }
end
end
because I added a convenience class-method, you can now calculate a result as follows:
PyramidCalculator.calculate([1,5,9,2,3,5,6])
My personal preference would be the last option :)
I would just do it as a two-liner.
a = a.each_cons(2).map{|e1, e2| e2 - e1} while a[1]
a.first # => 87
It's certainly easy enough to turn this into a simple function without hacking on the Array class:
def pyr(ary)
return ary[0] if ary.length < 2
pyr(ary.each_cons(2).map { |e| e[1] - e[0] })
end
p pyr [1,5,9,2,3,5,6] # => 87
Use return ary if you want the answer as a one-element array rather than a scalar.
If you prefer iteration to recursion or have a very large array:
def pyr(ary)
ary = ary.each_cons(2).map { |e| e[1] - e[0] } while ary.length > 1
ary
end
By encapsulating this as a function rather than doing it inline, you get the ability to do the operation on any number of arrays plus it's non-destructive on the original input array.
It's not necessary to compute the end value by successive computation of differences, which requires (n*(n-1)/2 subtractions and the same number of additions, where n is the size of the array a. Instead, we can compute that value by summing n terms of the form:
(-1)K+ibin_coeff(n-1,i)*a[i]
for i = 0..(n-1), where:
K equals 0 if the array has an even number of elements, else K equals 1; and
bin_coeff(n,i) is the binomial coefficient for choosing "n items i at a time" (n!/i!*(n-i)!).
I know what you're thinking: the calculation of each binomial coefficient will take some work. True, but that can be done in an efficient way (which I've not done below), by computing bin_coeff(n-1,i+1) from bin_coeff(n-1,i), etc. Of course, that's academic, as no one is likely to actually use the method I'm suggesting.
(I'm hoping nobody will demand a proof, but I'll try to oblige if a request is made.)
Code
class Fixnum
def factorial
(1..self).reduce(1) { |t,i| t*i }
end
def bin_coeff m
self.factorial/(m.factorial*(self-m).factorial)
end
end
def pyramid_sum(a)
n = a.size-1
sign = n.even? ? -1 : 1
(0..n).reduce(0) do |t,i|
sign = -sign
t + sign * n.bin_coeff(i) * a[i]
end
end
Examples
pyramid_sum [1, 5] #=> 4
pyramid_sum [1, 5, 9] # #=> 0
pyramid_sum [1, 5, 9, 2] #=> -11
pyramid_sum [1, 5, 9, 2, 3] #=> 30
pyramid_sum [1, 5, 9, 2, 3, 5] #=> -56
pyramid_sum [1, 5, 9, 2, 3, 5, 6] #=> 87
I have no clue how to call this in correct math-terms. Consider a method which takes two digits:
def num_of_sum(total, group_count)
end
where total is an integer and group_count is an integer.
How would I get a 'nicely' grouped Array of integers of group_count-length which sum up till total.
My spec would look like:
describe "number to sum of" do
it "grabs all numbers" do
expect(num_of_sum(10, 2)).to eq([5,5])
expect(num_of_sum(10, 3)).to eq([3,3,4])
expect(num_of_sum(20, 3)).to eq([6,7,7])
expect(num_of_sum(100, 3)).to eq([33,33,34])
expect(num_of_sum(100, 2)).to eq([50,50])
end
end
I tried this, which works:
def num_of_sum(total, in_groups_of)
result = []
section_count ||= (total.to_f / in_groups_of.to_f).round
while(total > 0)
total -= section_count
if (total - section_count) < 0 && (total + section_count).even?
section_count += total
total -= total
end
result << section_count
end
result
end
But, for instance, this spec doesn't work:
expect(num_of_sum(67,5)).to eq([13,13,13,14,14])
I need the array to contain numbers that are as close to each other as possible. But the array is limited to the length of the group_count.
Does someone know what the mathemetical name for this is, so I can search a bit more accurately?
The mathematical term for this is an integer partition
A more direct approach to this is to observe that if you do integer division (round down) of the total by the number of groups, then your sum would be short by total mod number_of_groups, so you just need to distribute that amount across the array:
def even_partition(total, number_of_groups)
quotient, remainder = total.divmod(number_of_groups)
(number_of_groups-remainder).times.collect {quotient} +
remainder.times.collect { quotient + 1}
end
def n_parts(num, groupcount)
div, mod = num.divmod(groupcount)
Array.new(groupcount-mod, div) + Array.new(mod, div+1)
end
n_parts(100,3) => [33, 33, 34]
Docs to Array.new and Fixnum.divmod
A naive implementation is like this:
Let's take example of (20, 3). You want three numbers as a result.
20 / 3 # => 6
This is your "base" value. Create an array of three sixes, [6, 6, 6]. That'll get you 18. Now you have to distribute remaining 2 as equally as possible. For example, enumerate array elements and increment each one by 1, until you have no value to distribute. Result is [7, 7, 6]. Good enough, I think.
Possible (working) implementation:
def breakdown(total, group_count)
avg_value, extra = total.divmod(group_count)
result = Array.new(group_count, avg_value)
extra.times do |i|
result[i] += 1
end
result
end
breakdown(10, 2) == [5, 5] # => true
breakdown(10, 3) == [4, 3, 3] # => true
breakdown(20, 3) # => [7, 7, 6]
I have no clue how it’s called, but here is a solution:
def num_of_sum sum, count
result = [i = sum / count] * count # prepare an array e.g. [3,3,3] for 10,3
result[sum - i * count..-1] + # these should be left intact
result[0...sum - i * count].map { |i| i + 1 } # these are ++’ed
end
Hope it helps.
Another way:
def floors_then_ceils(n, groups)
floor, ceils = n.divmod(groups)
groups.times.map { |i| (i < groups-ceils) ? floor : floor + 1 }
end
floors_then_ceils(10, 3)
#=> [3, 3, 4]
floors_then_ceils(9, 3)
#=> [3, 3, 3]
Alternatively, groups.times.map... could be replaced with:
Array.new(groups-ceils, floor).concat(Array.new(ceils, floor+1))
The object of my coding exercise is to get rid of duplicates in an array without using the uniq method. Here is my code:
numbers = [1, 4, 2, 4, 3, 1, 5]
def my_uniq(array)
sorted = array.sort
count = 1
while count <= sorted.length
while true
sorted.delete_if {|i| i = i + count}
count += 1
end
end
return sorted
end
When I run this, I get an infinite loop. What is wrong?
Can I use delete the way that I am doing with count?
How will it execute? Will count continue until the end of the array before the method iterates to the next index?
I did this with each or map, and got the same results. What is the best way to do this using each, delete_if, map, or a while loop (with a second loop that compares against the first one)?
Here is a clearly written example.
numbers = [1, 4, 2, 4, 3, 1, 5]
def remove_duplicates(array)
response = Array.new
array.each do |number|
response << number unless response.include?(number)
end
return response
end
remove_duplicates(numbers)
As others pointed out, your inner loop is infinite. Here's a concise solution with no loops:
numbers.group_by{|n| n}.keys
You can sort it if you want, but this solution doesn't require it.
the problem is that the inner loop is an infinite loop:
while true
sorted.delete_if {|i| i = i + count}
count += 1
end #while
you can probably do what you are doing but it's not eliminating duplicates.
one way to do this would be:
numbers = [1, 4, 2, 4, 3, 1, 5]
target = []
numbers.each {|x| target << x unless target.include?(x) }
puts target.inspect
to add it to the array class:
class ::Array
def my_uniq
target = []
self.each {|x| target << x unless target.include?(x) }
target
end
end
now you can do:
numbers = [1, 4, 2, 4, 3, 1, 5]
numbers.my_uniq
You count use Set that acts like an array with does not allow duplicates:
require 'set'
numbers = [1, 4, 2, 4, 3, 1, 5]
Set.new(numbers).to_a
#=> [1, 4, 2, 3, 5]
Try using Array#& passing the array itself as parameter:
x = [1,2,3,3,3]
x & x #=> [1,2,3]
This is one of the answer. However, I do not know how much of performance issue it takes to return unique
def my_uniq(ints)
i = 0
uniq = []
while i < ints.length
ints.each do |integers|
if integers == i
uniq.push(integers)
end
i += 1
end
end
return uniq
end
How can I multiply a number in an array by its position in the array and then add up the sum of the array in ruby?
I don't understand how to access the index of the array within the map function
For example: how can i get [5, 7, 13, 2]
to go to [5*0, 7*1, 13*2, 2*3]
then get the sum of this array.
ie
def array_method (numbers)
numbers.map{|i| i* ?????}
end
array_method([5, 7, 13, 2])
this isn't working either its returning an empty array and I don't know what i am doing wrong.
You can monkey patch the Array class if you want the method to be available to all arrays:
class Array
def sum_with_index
self.map.with_index { |element, index| element * index }.inject(:+)
end
end
Console output
2.0.0-p247 :001 > [5, 7, 13, 2].sum_with_index
=> 39
[5,7,13,2].map.with_index(&:*).inject(:+)
# => 39
[5,7,13,2].each_with_index.map{|value,index|value*index}.reduce{|a,b|a+b}
def array_method (numbers)
ans = 0
numbers.each_with_index {| num, idx | ans += (idx) * num }
end
Use inject
def dot_product_with_index(array)
(0..array.count-1).inject(0) {|r,i| r + array[i]*i}
end