`map`比'each`快吗?

时间:2015-07-21 01:50:05

标签: ruby

在迭代数组时mapeach更快吗?两者之间有速度差异吗?

  • 地图

    result = arr.map {|a| a + 2}
    
  • 每个

    result = []
    arr.each do |a| 
      result.push(a + 2)
    end
    

5 个答案:

答案 0 :(得分:8)

我想是的。

我已经尝试过这个测试

require "benchmark"

n=10000
arr=Array.new(10000,1)
Benchmark.bm do |x|
  #Map
  x.report do
    n.times do
      result = arr.map {|a| a + 2}
    end
  end


  #Each
  x.report do
    n.times do
      result = []
      arr.each do |a|
        result.push(a + 2)
      end
    end
  end
end

我得到了这个时间

       user     system      total        real
   5.790000   0.060000   5.850000 (  5.846956)
   8.210000   0.030000   8.240000 (  8.233849)

似乎更快地映射

我看过这段视频http://confreaks.tv/videos/goruco2015-how-to-performance 她展示了许多红宝石配置文件和工具,如果你有兴趣改善你的表现,你会发现很多提示。

<强>加入

这对我来说是一种疯狂的行为!

require "benchmark"

n=10000
arr=Array.new(10000,1)
Benchmark.bm do |x|
  #Map
  x.report do
    n.times do
      result = arr.map {|a| a + 2}
    end
  end
  #Each and push
  x.report do
    n.times do
      result = []
      arr.each do |a|
        result.push(a + 2)
      end
    end
  end

 #Each and <<
  x.report do
    n.times do
      result = []
      arr.each do |a|
        result << (a + 2)
      end
    end
  end
end

和结果

       user     system      total        real
   5.880000   0.080000   5.960000 (  5.949504)
   8.160000   0.010000   8.170000 (  8.164736)
   6.630000   0.010000   6.640000 (  6.632686)

是运营商&#34;&lt;&lt;&#;比推方法更快?我没想到,我认为这是一种别名。

答案 1 :(得分:5)

each应该比map更快,因为前者不会修改/创建任何内容,而后者会这样做。但是在你的代码中,你正在比较不同的东西。 push花费时间。您的代码与比较eachmap无关。

答案 2 :(得分:3)

MRI v2.2.2中的

This is the source for each

               VALUE
rb_ary_each(VALUE array)
{
    long i;
    volatile VALUE ary = array;

    RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
    for (i=0; i<RARRAY_LEN(ary); i++) {
        rb_yield(RARRAY_AREF(ary, i));
    }
    return ary;
}

this is the source for map

               static VALUE
rb_ary_collect(VALUE ary)
{
    long i;
    VALUE collect;

    RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
    collect = rb_ary_new2(RARRAY_LEN(ary));
    for (i = 0; i < RARRAY_LEN(ary); i++) {
        rb_ary_push(collect, rb_yield(RARRAY_AREF(ary, i)));
    }
    return collect;
}

请注意,mapeach几乎相同(这是预期的),但map也需要创建一个数组,然后执行推送。您在Ruby中的each版本基本上是做同样的事情,但是你的是Ruby,这是C,所以通过在较高级别重新创建较低级别会有额外的开销,并且C通常比Ruby更快反正。

答案 3 :(得分:1)

不确定,但具有指示性:

BufferStrategy

这是两种方法的不完美基准。询问matrix[n][n]require 'fruity' def mapit(a) a.map {|e| e + 2}.size end def eachit(a) result = [] a.each do |e| result.push(e + 2) end.size end a = Array.new(1_000) { rand 10 } compare do map { mapit(a) } each { eachit(a) } end #=> Running each test 32 times. Test will take about 1 second. #=> map is faster than each by 2x ± 0.1 a = Array.new(10_000) { rand 10 } compare do map { mapit(a) } each { eachit(a) } end #=> Running each test 4 times. Test will take about 1 second. #=> map is faster than each by 50.0% ± 10.0% a = Array.new(100_000) { rand 10 } compare do map { mapit(a) } each { eachit(a) } end #=> Running each test once. Test will take about 1 second. #=> map is faster than each by 2x ± 0.1 是否更快只适用于非常具体的比较。

答案 4 :(得分:0)

三年后我来了,因为我想回答OP在不同情况下提出的相同问题。很明显,如果使用mapeach来创建新数组,则map会更快,正如现有答案所解释的那样。

但是,在我看来,真正的问题是使用map创建具有某些修改的新数组还是使用each对现有数组进行相同的修改更快。为了对此进行测试,我修改了接受答案中的基准:

require "benchmark"

def mapmethod(input)
  input.map(&:reverse)
end

def eachmethod(input)
  input.map(&:reverse!)
end

n=10000
arr=Array.new(10000,'ab')
Benchmark.bm do |x|
  #Map
  x.report do
    n.times do
      mapmethod(arr)
    end
  end

  #Each
  x.report do
    n.times do
      eachmethod(arr)
    end
  end
end

我得到了这个结果:

   user     system      total        real
27.362799   0.103154  27.465953 ( 28.441034)
15.204973   0.392920  15.597893 ( 15.993965)

在我看来,这是一个非常有力的指标,表明修改现有阵列比创建具有相同修改的新阵列要快得多。因此,如果您不需要新的数组,我将使用each,如果需要,我将使用map