Is `map` faster than` each`?

Is it map

faster when iterating over an array than each

? Is there a speed difference between the two?

  • Map

    result = arr.map {|a| a + 2}
    
          

  • Every

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

+5


source to share


5 answers


I think yes.

I 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 it once

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

      

Looks like the card is faster

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



added

This is 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)

      

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

+7


source


each

should be faster than map

that since the former does not change / create anything while the latter does. But in your code, you are comparing different things. push

this time. Your code is not related to comparison each

and map

.



+5


source


This is the source foreach

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 formap

:

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

      

Note that map

and are each

almost the same (which is to be expected), but map

also an array needs to be created and then it is clicked. Your each

Ruby version basically does the same, but your Ruby is C, so the additional overhead can be increased by recreating the lower level at a higher level, and C is faster than Ruby anyway.

+3


source


Not definitive, but indicative:

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

      

This is an imperfect criterion for your two methods. Asking whether faster each

or map

makes sense only for very specific comparisons.

+1


source


I ran into this three years later because I wanted to answer the same question the OP asked under different circumstances. It is clear that if you use map

and each

to create a new array it map

will be faster as the existing answers explain.

However, it seems to me that the real question is whether it is faster to create a new array with some modifications using, map

or to make the same changes to an existing array using each

. To test this, I modified the test in the accepted answer to look like this:

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

      

And I got this result:

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

      

This seems to me to be a pretty strong indication that changing an existing array is much faster than creating a new one with the same modifications. So if you don't need a new array I would use each

, and if you need I would use map

.

0


source







All Articles