What's the Efficient Way to Multiply Two Arrays and Get Sum of Multiplied Values in Ruby

What's the efficient way to multiply two arrays and get sum of multiplied values in Ruby?

Update

I've just updated benchmarks according to new comments. Following Joshua's comment, the inject method will gain a 25% speedup, see array walking without to_a in the table below.

However since speed is the primary goal for the OP we have a new winner for the contest which reduces runtime from .34 to .22 in my benchmarks.

I still prefer inject method because it's more ruby-ish, but if speed matters then the while loop seems to be the way.

New Answer

You can always benchmark all these answers, I did it for curiosity:

> ./matrix.rb 
Rehearsal --------------------------------------------------------------
matrix method 1.500000 0.000000 1.500000 ( 1.510685)
array walking 0.470000 0.010000 0.480000 ( 0.475307)
array walking without to_a 0.340000 0.000000 0.340000 ( 0.337244)
array zip 0.590000 0.000000 0.590000 ( 0.594954)
array zip 2 0.500000 0.000000 0.500000 ( 0.509500)
while loop 0.220000 0.000000 0.220000 ( 0.219851)
----------------------------------------------------- total: 3.630000sec

user system total real
matrix method 1.500000 0.000000 1.500000 ( 1.501340)
array walking 0.480000 0.000000 0.480000 ( 0.480052)
array walking without to_a 0.340000 0.000000 0.340000 ( 0.338614)
array zip 0.610000 0.010000 0.620000 ( 0.625805)
array zip 2 0.510000 0.000000 0.510000 ( 0.506430)
while loop 0.220000 0.000000 0.220000 ( 0.220873)

Simple array walking wins, Matrix method is worse because it includes object instantiation. I think that if you want to beat the inject while method (to beat here means an order of magnitude fastest) you need to implement a C extension and bind it in your ruby program.

Here it's the script I've used

#!/usr/bin/env ruby

require 'benchmark'
require 'matrix'

array_A = [1, 2, 1, 4, 5, 3, 2, 6, 5, 8, 9]
array_B = [3, 2, 4, 2, 5, 1, 3, 3, 7, 5, 4]

def matrix_method a1, a2
(Matrix.row_vector(a1) * Matrix.column_vector(a2)).element(0,0)
end

n = 100000

Benchmark.bmbm do |b|
b.report('matrix method') { n.times { matrix_method(array_A, array_B) } }
b.report('array walking') { n.times { (0...array_A.count).to_a.inject(0) {|r, i| r + array_A[i]*array_B[i]} } }
b.report('array walking without to_a') { n.times { (0...array_A.count).inject(0) {|r, i| r + array_A[i]*array_B[i]} } }
b.report('array zip') { n.times { array_A.zip(array_B).map{|i,j| i*j }.inject(:+) } }
b.report('array zip 2') { n.times { array_A.zip(array_B).inject(0) {|r, (a, b)| r + (a * b)} } }
b.report('while loop') do
n.times do
sum, i, size = 0, 0, array_A.size
while i < size
sum += array_A[i] * array_B[i]
i += 1
end
sum
end
end
end

How can I multiply two arrays in Ruby?

a.zip(b).map{|x, y| x * y}

This works because zip combines the two arrays into a single array of two element arrays. i.e.:

a = [3, 2, 1]
b = [1, 2, 3]
a.zip(b)
#=> [[3, 1], [2, 2], [1, 3]]

Then you use map to multiply the elements together. This is done by iterating through each two element array and multiplying one element by the other, with map returning the resulting array.

a.zip(b).map{|x, y| x * y}
#=> [3, 4, 3]

Calculate running total of multiple values in Ruby

UPDATE1:

it doesn't change anything.
You can still apply the codes.

(0..3).each do |value|
# First loop
values << [4444.33,0,333.444,0]
# Second loop
values << [3333.444,0,1123.44,5444]
# Third loop
values << [321112.4,443.3,0,4444]
# Here I need to add each array with the next one
values.transpose.map {|x| x.reduce(0, :+)}
end



1st ANSWER:

use mapping. just one line.

values.transpose.map {|x| x.reduce(0, :+)}

Ruby - Finding if any two numbers in an array if multiplied equal to a third number

I'd like to show a slightly more complicated version

def multiply_to (array,n)
numbers = array.map{|x|[x]}
pairs = []

for i in 0..numbers.length-1
pairs.concat numbers[i].product(array - numbers[i])
end

puts "#{pairs.count{|a,b|a * b == n} > 0}"

end

In languages that do not offer the functionality of Ruby, you need to do a little work.

We can store our combos in an array called pairs

We'd like to iterate over every number in the array. For all those numbers, we want to take the product of an array with that element and all the other numbers of the array.

This gives us all our combos of two numbers. We can test this method out as follows

multiply_to([4,7,9,13], 63)
=> true

Ruby - Sort array of arrays based on sum and object type

You can use:

  • Array#select to extract the arrays based on a condition
  • Enumerable#grep_v to extract non-integers
  • Array#sum to calculate the sums (using to_f for conversion)
elements.select do |ary|
ary.grep_v(Integer).sum(&:to_f) * 2 >= ary.sum(&:to_f)
end
#=> [[1, 2, "3", "4"], ["1", 2, 3, "4.0"], [1, 2, 3.0, 4.0, 5.0]]

You could also pass the to_f-call to grep_v, i.e. ary.grep_v(Integer, &:to_f).sum but I prefer to have identical sum-calls on both sides.

How do I perform vector addition in Ruby?

See the Vector class:

require "matrix"

x = Vector[100, 100]
y = Vector[2, 3]
print x + y

E:\Home> ruby t.rb
Vector[102, 103]

See vectorops for additional operations on vectors:

… the following operations work like expected

  v1 = Vector[1,1,1,0,0,0]
v2 = Vector[1,1,1,1,1,1]

v1[0..3]
# -> Vector[1,1,1]

v1 += v2
# -> v1 == Vector[2,2,2,1,1,1]

v1[0..3] += v2[0..3]
# -> v1 == Vector[2,2,2,0,0,0]

v1 + 2
# -> Vector[3,3,3,1,1,1]

See also vectorops.



Related Topics



Leave a reply



Submit