Ruby on rails Ruby/Rails中的sum或reduce(:+;)更好吗?除了速度,还有其他考虑吗?
对于长数组来说#sum比#reduce快,而对于短数组来说基本上是一样的Ruby on rails Ruby/Rails中的sum或reduce(:+;)更好吗?除了速度,还有其他考虑吗?,ruby-on-rails,ruby,Ruby On Rails,Ruby,对于长数组来说#sum比#reduce快,而对于短数组来说基本上是一样的 def reduce_t(s,f) start = Time.now puts (s..f).reduce(:+) #Printing the result just to make sure something is happening. finish = Time.now puts finish - start end def sum_t(s,f) start = Time.now puts (
def reduce_t(s,f)
start = Time.now
puts (s..f).reduce(:+) #Printing the result just to make sure something is happening.
finish = Time.now
puts finish - start
end
def sum_t(s,f)
start = Time.now
puts (s..f).sum
finish = Time.now
puts finish - start
end
irb(main):078:0> sum_t(1,10); reduce_t(1,10)
55
0.000445
55
0.000195
=> nil
irb(main):079:0> sum_t(1,1000000); reduce_t(1,1000000)
500000500000
8.1e-05
500000500000
0.101487
=> nil
除了速度,还有其他考虑吗?有没有哪种情况下,用“减少”而不是“求和”来达到同样的目的,一个简单的求和会更好
编辑
正确地指出,在得出关于计时结果的结论之前,我应该进行多次迭代。我没有使用基准测试
,因为我还不熟悉它,但我希望我下面所写的内容将是充分和令人信服的
def sum_reduce_t(s,f)
time_reduce = 0
time_sum = 0
reduce_faster = 0
sum_faster = 0
30.times do
start_reduce = Time.now
(s..f).reduce(:+)
finish_reduce = Time.now
time_reduce += (finish_reduce - start_reduce)
start_sum = Time.now
(s..f).sum
finish_sum = Time.now
time_sum += (finish_sum - start_sum)
if time_sum > time_reduce
reduce_faster += 1
else
sum_faster += 1
end
end
puts "Total time (s) spent on reduce: #{time_reduce}"
puts "Total time (s) spent on sum: #{time_sum}"
puts "Number of times reduce is faster: #{reduce_faster}"
puts "Number of times sum is faster: #{sum_faster}"
end
irb(main):205:0> sum_reduce_t(1,10)
Total time (s) spent on reduce: 0.00023900000000000004
Total time (s) spent on sum: 0.00015400000000000003
Number of times reduce is faster: 0
Number of times sum is faster: 30
=> nil
irb(main):206:0> sum_reduce_t(1,100)
Total time (s) spent on reduce: 0.0011480000000000004
Total time (s) spent on sum: 0.00024999999999999995
Number of times reduce is faster: 0
Number of times sum is faster: 30
=> nil
irb(main):207:0> sum_reduce_t(1,1000)
Total time (s) spent on reduce: 0.004804000000000001
Total time (s) spent on sum: 0.00019899999999999996
Number of times reduce is faster: 0
Number of times sum is faster: 30
=> nil
irb(main):208:0> sum_reduce_t(1,10000)
Total time (s) spent on reduce: 0.031862
Total time (s) spent on sum: 0.00010299999999999996
Number of times reduce is faster: 0
Number of times sum is faster: 30
=> nil
irb(main):209:0> sum_reduce_t(1,100000)
Total time (s) spent on reduce: 0.286317
Total time (s) spent on sum: 0.00013199999999999998
Number of times reduce is faster: 0
Number of times sum is faster: 30
=> nil
irb(main):210:0> sum_reduce_t(1,1000000)
Total time (s) spent on reduce: 2.7116779999999996
Total time (s) spent on sum: 0.00021200000000000008
Number of times reduce is faster: 0
Number of times sum is faster: 30
=> nil
我的问题仍然是:有没有使用“减少”而不是“求和”的时候是有意义的?好的,我认为这些评论可以结合起来形成一个好的答案,不过如果有人想更深入地解释,我当然会接受其他人 重点是:
- sum方法在当前版本的Ruby中不可用,但在将来可以使用。我是通过Rails使用它的,在Rails可用的地方
- 求和法对大型数组求和确实更快
- 将旧代码从reduce改为sum可能不值得,除非存在与超长数组相关的性能问题
- “考虑到数组的#和是,它的速度应该不会太快。”
- Reduce做了很多其他的事情(
,Reduce(:-)
,等等),所以它不应该被认为是无用的。如果sum方法可用,那么它就不是求和一个巨大数组的最佳选择Reduce(:*)
- 我认为,最重要的一点是:如果您需要代码与Ruby的早期版本兼容,reduce更安全
- “当您添加许多小值时,总和确实会增加,这在inject&:+中不会发生。”(@matt)
- reduce方法可以生成一些有趣的表情
- 除了速度,还有其他考虑吗是(兼容性,将非常大的数字添加到非常小的数字中)
- 是否存在使用#reduce更好的情况 不是为了达到同样的目的而求和,而是简单的求和是 (兼容性)
sum
的行为和结果与inject&:+
不同的一种方式是对浮点值求和
如果将大的浮点值添加到小的浮点值,结果通常与大的浮点值相同:
> 99999999999999.98 + 0.001
=> 99999999999999.98
这可能会导致在添加浮点数组时出错,因为较小的值实际上会丢失,即使有很多值
例如:
> a = [99999999999999.98, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001]
=> [99999999999999.98, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001]
> a.inject(&:+)
=> 99999999999999.98
在本例中,您可以根据需要随时添加0.001
,它永远不会更改结果的值
使用“求和浮点数时”可减少此错误:
> a.sum
=> 100000000000000.0
(请注意这里的结果,您可能希望数组中有10个
0.001
的值以.99
结尾。这只是正常的浮点行为,也许我应该尝试找到一个更好的示例。重要的一点是,当您添加大量小值时,总和确实会增加,而inject&::+
)@AndreyDeineko它在ruby 2.4.Wohoo!中。(1)您需要进行多次迭代才能获得任何有用的计时结果,也许您应该使用标准库中的基准测试
,而不是自己滚动。(2)鉴于此,速度更快也就不足为奇了。@Anthony,这应该是一个惊喜。Leo,你应该添加一个Rail标签,因为Ruby v2.4.0还没有发布。我的意思是……这是个问题吗?这似乎是一种毫无意义的优化;任何一种都是线性时间运行的。Leo,我在v2.3.0和[1,2,3].sum#=>NoMethodError:[1,2,3]:数组的未定义方法“sum”
。我希望执行速度的差异不会达到。哪一个更优雅?你告诉我。很好的总结!你还可以添加@matt关于sum改进浮点行为的解释吗?