Reputation: 270
For a given array, I want to compute products always leaving one value out. For example, for input [1, 2, 3, 4]
I want output [2*3*4, 1*3*4, 1*2*4, 1*2*3]
, i.e., [24, 12, 8, 6]
.
def array_product(array)
arr_lgth=array.length
array_d=array.dup
sum=[]
itr=0
while itr<(arr_lgth)
p itr
p array
array[itr]=1
sum << array.reduce(1,:*);
array=array_d
itr+=1
end
return sum
end
array_product([1,2,3,4])
As I track the iteration and array, I get the following results that I do not understand:
0
[1, 2, 3, 4]
1
[1, 2, 3, 4]
2
[1, 1, 3, 4]
3
[1, 1, 1, 4]
Shouldn't the array be assigned the duplicate values at the end of each while loop iteration?
Upvotes: 2
Views: 487
Reputation: 37517
Basically you want to find the product of each combination of three numbers.
[1,2,3,4].combination(3).map{|c| c.reduce(:*)}
Upvotes: 3
Reputation: 28626
Your mistake is that you duplicate the given array only once. For the first index you then work with the given array, and then you set array=array_d
and from then on for all remaining indexes you're working on that duplicate the whole time, writing more and more 1
s into it.
The simplest way to fix it is to use array=array_d.dup
there instead, i.e., just append .dup
there. Then you don't work on the same array over and over again but instead always reset to the original (duplicated) values as you intended.
But it's better to just make a duplicate right before the calculation of each product, and use that fresh duplicate to compute the product. So change your inner part to this:
array_d = array.dup
array_d[itr] = 1
sum << array_d.reduce(:*)
The whole method made rubyish:
def array_product(array)
array.each_index.map do |i|
dup = array.dup
dup[i] = 1
dup.reduce(:*)
end
end
By the way, note that you don't need to initialize reduce
with 1
.
Oh and in case your array doesn't have zeros, you could also just compute the product of all numbers once and then divide it by each number. That's much faster:
def array_product(array)
p = array.reduce(:*)
array.map { |x| p / x }
end
Upvotes: 2
Reputation: 211670
There's a lot going on in this code for what should be a simple problem. One of the strengths of Ruby is being able to express a simple solution to this exact problem. I think what you're trying to do comes out as:
def array_product(array)
# Convert each index in the array...
array.each_index.map do |i|
# ...into a copy of the array with that index set as 1...
array.each_with_index.map do |a, j|
i == j ? 1 : a
end.reduce(1, :*) # ...multiplied together.
end
end
It's rare to see conventional for
loops, use of iterator-like variables and such in Ruby because there's a wealth of tools in the Enumerable library that makes them mostly obsolete.
The key here is to use tools like map
whenever possible in preference to dup
and some hammering around with the data using index variables. The map
function is key for when you need a 1:1 "mapping" of the original data into an array of identical length where you get to decide how to handle each element individually.
This code produces:
array_product([ 1, 2, 3 ])
# => [6, 3, 2]
Upvotes: 5