Ruby Map/Reduce功能是否必须高效?

Ter*_* Li 3 ruby reduce functional-programming inject

b1 = Time.now
puts (1..100000).inject(0) { |x, y| x + y }
a1 = Time.now
puts "Time for inject: #{a1 - b1}"

b2 = Time.now
sum = 0
(1..100000).each do |value|
    sum += value
end
puts sum
a2 = Time.now
puts "Time for each: #{a2 - b2}"
Run Code Online (Sandbox Code Playgroud)

上面的Ruby代码比较了两种求和整数的方法.令我惊讶的是,更优雅的注入减少方法胜过另一方.为什么会这样?人们为什么要使用低效注入减少?只是因为它很优雅?

PS:感谢所有鼓舞人心的答案.我的目的是询问导致这些差异的幕后情况.

Jon*_*des 6

在这种情况下我会用一点点数学:

require "benchmark"

N = 5_000_000

Benchmark.bmbm do |bm|
  bm.report "inject 1" do
    (1..N).inject(0) { |x, y| x + y }
  end

  bm.report "inject 2" do
    (1..N).inject(:+)
  end

  bm.report "each" do
    sum = 0
    (1..N).each do |value|
      sum += value
    end
  end

  bm.report "sum of finite arithmetic progression" do
    ((1 + N) * N) / 2
  end
end
Run Code Online (Sandbox Code Playgroud)

结果是:

% ruby sum.rb
Rehearsal ------------------------------------------------------------------------
inject 1                               0.500000   0.000000   0.500000 (  0.507497)
inject 2                               0.320000   0.000000   0.320000 (  0.322675)
each                                   0.370000   0.000000   0.370000 (  0.380504)
sum of finite arithmetic progression   0.000000   0.000000   0.000000 (  0.000005)
--------------------------------------------------------------- total: 1.190000sec

                                           user     system      total        real
inject 1                               0.500000   0.000000   0.500000 (  0.507697)
inject 2                               0.320000   0.000000   0.320000 (  0.322323)
each                                   0.370000   0.000000   0.370000 (  0.380307)
sum of finite arithmetic progression   0.000000   0.000000   0.000000 (  0.000004)
% 
Run Code Online (Sandbox Code Playgroud)

更好的数学总是更快:)


mol*_*olf 5

是的,代码可读性比微优化更重要.即使采用数百万元素的总和,差异也几乎不可察觉.此外,两种方法都是O(n),因此随着元素数量的增加,两种方法都不会明显优于另一种方法.

正如其他人所指出的那样,inject(:+)还是要快一点.即使它不是,选择最容易看到的那个,并且不要担心性能上的细微差别.这可能不是您的应用程序的瓶颈.

require "benchmark"

N = 5_000_000

Benchmark.bmbm do |bm|
  bm.report "inject 1" do
    (1..N).inject(0) { |x, y| x + y }
  end

  bm.report "inject 2" do
    (1..N).inject(:+)
  end

  bm.report "each" do
    sum = 0
    (1..N).each do |value|
      sum += value
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

结果:

               user     system      total        real
inject 1   0.610000   0.000000   0.610000 (  0.613080)
inject 2   0.370000   0.000000   0.370000 (  0.370892)
each       0.570000   0.000000   0.570000 (  0.568266)
Run Code Online (Sandbox Code Playgroud)