In Ruby, we can use Enumerable#map
to process collections. The map
method takes a block:
1
2
3
names = %w(ant)
names.map{ |x| x.upcase }
We can also pass in custom objects which respond to to_proc
:
1
2
3
4
5
6
7
8
class Double
def to_proc
proc{ |n| n * 2 }
end
end
arr = [1.0, 2.0, 3.0]
arr.map(&Double.new) # => [2.0, 4.0, 6.0]
In Ruby 2.3+, Hash
has a to_proc
method which means we can pass a hash into a collection:
1
2
3
h = { foo: 1, bar: 2, baz: 3 }
[:foo, :bar].map(&h) #=> calls h.to_proc
I decided to do a quick benchmark on how efficient the block method of map runs compared to the using a proc:
The results show that using proc
is slower than calling map
with a block:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#/usr/bin/env ruby
require "benchmark/ips"
arr = [1.0, 2.0, 3.0]
h = { foo: 1, bar: 2, baz: 3 }
class Double
def to_proc
proc{ |n| n * 2 }
end
end
Benchmark.ips do |x|
x.report("arr.map{ |x| x*2 }"){
arr.map{ |x| x*2 }
}
x.report("arr.map(&Double.new)"){
arr.map(&Double.new)
}
x.report("[:foo, :bar].map"){
[:foo, :bar].map{ |x| h[x] }
}
x.report("[:foo, :bar].map(&h)"){
[:foo, :bar].map(&h)
}
x.compare!
end
From the results, I learnt that using dynamic procs may be more suited for smaller collections with map
. For larger collections, it is more efficient to stick to the block method.
Happy Hacking and stay curious!!