Is `map` faster than` each`?
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.
source to share
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.
source to share
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.
source to share
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
.
source to share