红宝石按位产品

时间:2014-11-25 11:57:37

标签: ruby performance

我有一个分配,我必须编写一个函数,它需要两个整数并返回它的按位产品。按位乘积等于这两者之间所有数字的按位求和(&)。

例如:251253的按位产品为:

irb(main):164:0> 251 & 252
=> 248
irb(main):165:0> 252 & 253
=> 252
irb(main):166:0> 248 & 252
=> 248 # this a bitwise & of these two between 251 & 253

我的功能:

def solution(m,n)
  (m..n).to_a.inject{|sum, x| sum &= x}
end

测试:

irb(main):160:0> (251..253).to_a.inject{|sum, x| sum &= x}
=> 248 #same result

该计划的评估:

  

正确率100%
  表现0%

任何人都可以解释这个功能的性能吗?提前谢谢!

修改

由于此处未定义性能,您是否可以提供功能分析,例如,真正的大输入和批评/建议更好/更有效的解决方案?

P.S。对于评论员来说,我会按照建议进行操作!

2 个答案:

答案 0 :(得分:2)

跟进我的评论,您可以使用Benchmark进行实验:

def solution(m,n)
  (m..n).to_a.inject{|sum, x| sum &= x}
end

def solution2(m,n)
  (m..n).reduce(:&)
end

n = 50000
Benchmark.bm(7) do |b|
  b.report("orig:") { n.times do; solution(128,253); end }
  b.report("new: ") { n.times do; solution2(128,253); end }
end

这是我得到的:

              user     system      total        real
orig:     1.560000   0.000000   1.560000 (  1.557156)
new:      0.640000   0.000000   0.640000 (  0.634063)

您似乎没有别的选择,只能执行上述操作,尝试找到更快的算法,并运行测试,直到您在性能表上注册。

答案 1 :(得分:1)

这里最明显的性能问题是转换为数组(to_a),这不是必需的。您可以拨打reduceinject(看似相同)任意EnumerableRange也包括它。 Enumerable基本上是可以产生有限(它可论证的,但大多数是真的)元素序列的所有东西。 Range似乎适合,如果被视为一组整数。

为了迭代包含此范围内元素的数组,首先要创建一个数组并用元素填充它(通过迭代Range)。然后,您将迭代应用您的操作的结果数组。所以你创建一个数组是为了迭代它,填充它,使用它,扔掉它。如果范围很大,则需要相当大的内存分配。

下一个并不重要,但减少了你拥有的代码量,需要一些关于Ruby中运算符内部实现的知识。当您撰写a&b时,您实际上正在a.&(b):在号码上调用&方法。

你在街区中遇到的sum实际上不是某种accumulator,你实际上并不需要在那里分配任何东西,sum是一个中间值,添加新元素的结果实际上应该是返回值。由于赋值返回指定的值,因此它甚至可以这样工作。证明是这样的:

(251..253).inject{|sum, x| sum & x } # => 248, as expected

...结果证明,这个块很简单:取一个值,用另一个值调用一个方法。由于inject在每次迭代时都会获取一对值,因此您可以给它一个方法名称并让它处理这种情况。 Ruby中的方法名称通常用以下符号引用:

(251..253).inject(:&) # => 248, as expected

好吧,大约两倍的代码,更少的动作和更少的对象,但结果相同。

def solution(m,n)
  (m..n).inject(:&)
end

我们没有密切关注inject。你能否在性能方面击败inject?它不太可能,它是一种C方法,在这里完全用于它的目的,您可以使用宝石prypry-doc轻松查找(安装,启动{{1}并输入pry):

show-source Range#inject