在
Ruby中乘以两个数组并获得乘法值之和的有效方法是什么?
我在Ruby中有两个数组:
我在Ruby中有两个数组:
array_A = [1,2,1,4,5,3,6,8,9] array_B = [3,7,4]
我的目标是得到array_A * array_B的和值,即1 * 3 2 * 2 1 * 4 … 8 * 5 9 * 4.
因为我需要在我的应用程序中计算它们数百万次,所以进行此类计算的最有效方法是什么?
它就像一个矩阵计算:1 * N矩阵* N * 1矩阵或矢量点积.
解决方法
更新
我刚刚根据新评论更新了基准测试.在Joshua’s comment之后,注入方法将获得25%的加速,参见下表中没有to_a的数组行走.
然而,由于速度是OP的主要目标,我们有a new winner for the contest,它在我的基准测试中将运行时间从.34减少到.22.
我仍然更喜欢注入方法,因为它更像ruby-ish,但如果速度很重要,那么while循环似乎就是这样.
新答案
您可以随时对所有这些答案进行基准测试,我是出于好奇而做到的:
> ./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)
简单的数组行走胜利,Matrix方法更糟糕,因为它包括对象实例化.我认为,如果你想击败注入方法(在这里击败意味着一个数量级最快),你需要实现一个C扩展并将其绑定在你的ruby程序中.
这是我用过的剧本
#!/usr/bin/env ruby require 'benchmark' require 'matrix' array_A = [1,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,array_A.size while i < size sum += array_A[i] * array_B[i] i += 1 end sum end end end