TL;DR The value side is
--Depth 1
The fastest speed is each_value
If you want to continue the method chain, you can think of flat_map
.
--When you want to flatten everything at a depth of 2 or more
values.flatten
is fast, but I like it because it is not so fast as each_value + flatten
.
Execution environment Ruby 2.7.1
sample = { a: [1, 2, 3], b: [2, 3, 4], c: [3, 4, 5] }
ary = []
sample.each { |_k, v| ary.concat(v) }
ary
# => [1, 2, 3, 2, 3, 4, 3, 4, 5]
ary = []
sample.each_value { |v| ary.push(*v) } #The above example is also okay with push instead of concat
ary
# => [1, 2, 3, 2, 3, 4, 3, 4, 5]
sample.values.flatten
# => [1, 2, 3, 2, 3, 4, 3, 4, 5]
# ruby 2.If it is 7,
sample.flat_map { _2 }
# => [1, 2, 3, 2, 3, 4, 3, 4, 5]
# _If 2 cannot be used
sample.flat_map { |_, v| v }
# => [1, 2, 3, 2, 3, 4, 3, 4, 5]
# flat_If you want to show here what the value of the receiver of the map is, I think it may be a good idea to write it.
sample.flat_map { |_, number_ary| number_ary }
# => [1, 2, 3, 2, 3, 4, 3, 4, 5]
When you want to retrieve the value of depth 1 as a flat Array
The results are as follows. (Since it is a number of how many loops can be rotated per second, it is faster to make a big one)
Comparison:
each_value: 2859228.9 i/s
each concat: 2745728.9 i/s - same-ish: difference falls within error
flat_map(_,v): 1986117.7 i/s - 1.44x (± 0.00) slower
flat_map(_2): 1971975.8 i/s - 1.45x (± 0.00) slower
values flatten: 918971.6 i/s - 3.11x (± 0.00) slower
require 'benchmark/ips'
sample = { a: [1, 2, 3], b: [2, 3, 4], c: [3, 4, 5] }
def method_1(h)
ary = []
h.each { |_k, v| ary.concat(v) }
ary
end
def method_2(h)
ary = []
h.each_value { |v| ary.push(*v) }
ary
end
def method_3(h)
h.values.flatten
end
def method_4(h)
h.flat_map { _2 }
end
def method_5(h)
h.flat_map { |_, v| v }
end
Benchmark.ips do |x|
x.config(:time => 20, :warmup => 2)
x.report("each concat") { method_1(sample) }
x.report("each_value ") { method_2(sample) }
x.report("values flatten") { method_3(sample) }
x.report("flat_map(_2)") { method_4(sample) }
x.report("flat_map(_,v)") { method_5(sample) }
x.compare!
end
When you want to flatten everything at a depth of 2 and take it out
Comparison:
values flatten: 800647.1 i/s
each_value.flatten: 759526.1 i/s - 1.05x (± 0.00) slower
flat_map flatten: 676500.5 i/s - 1.18x (± 0.00) slower
each_value in flatten: 468859.1 i/s - 1.71x (± 0.00) slower
require 'benchmark/ips'
sample = { a: [1, 2, [3]], b: [2, 3, [4]], c: [3, 4, [5]] }
def method_1(h)
ary = []
h.each_value { |v| ary.push(*v.flatten) }
ary
end
def method_2(h)
ary = []
h.each_value { |v| ary.push(*v) }
ary.flatten
end
def method_3(h)
h.values.flatten
end
def method_4(h)
h.flat_map { _2 }.flatten
end
Benchmark.ips do |x|
x.config(:time => 20, :warmup => 2)
x.report("each_value in flatten") { method_1(sample) }
x.report("each_value.flatten") { method_2(sample) }
x.report("values flatten") { method_3(sample) }
x.report("flat_map flatten") { method_4(sample) }
x.compare!
end
It is the fastest to do with each_value. (It's not much different from using each, but it's usually each_value considering readability) If it is flat_map, the return value will be the desired value and it is easy to continue the method chain, but it is late values.flatten is quite slow
values.flatten
is faster, but it's similar to each_value + flatten
.
Execution environment Ruby 2.7.1
Recommended Posts