Is `map` faster than `each`?

I think yes.

I've tried this test

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

And I got this times

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

Seems like map it's faster

I saw this video http://confreaks.tv/videos/goruco2015-how-to-performance she shows many ruby profiles and tools, if you are interested to improve your performance you will find a lot of tips there.

added

This is a crazy behavior for me!

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

and the result

       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)

is the operator "<<" faster than method push? I didn't expect that, I thought that was a kind of alias.


each should be faster than map since the former does not modify/create anything while the latter does. But in your code, you are comparing different things. It is push that is taking time. Your code is irrelevant from comparing each and map.


This is the source for each in MRI v2.2.2:

               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;
}

and 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;
}

Notice that map and each are almost the same (which is to be expected) but map also needs to create an array, and then it does a push. Your version of each in Ruby is basically doing the same thing, but yours is Ruby, this is C, so there will be extra overhead through recreating the lower level at the higher, and that C is faster than Ruby in general anyway.

Tags:

Ruby