我有一个分配,我必须编写一个函数,它需要两个整数并返回它的按位产品。按位乘积等于这两者之间所有数字的按位求和(&
)。
例如:251
和253
的按位产品为:
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。对于评论员来说,我会按照建议进行操作!
答案 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
),这不是必需的。您可以拨打reduce
和inject
(看似相同)任意Enumerable
,Range
也包括它。 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方法,在这里完全用于它的目的,您可以使用宝石pry
和pry-doc
轻松查找(安装,启动{{1}并输入pry
):
show-source Range#inject