[RUBY] Speed comparison when the value side of Hash wants to retrieve all with array

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

pattern

sample = { a: [1, 2, 3], b: [2, 3, 4], c: [3, 4, 5] }
  1. each
ary = []
sample.each { |_k, v| ary.concat(v) }
ary
# =>  [1, 2, 3, 2, 3, 4, 3, 4, 5]
  1. each_value
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]
  1. values + flatten
sample.values.flatten
# =>  [1, 2, 3, 2, 3, 4, 3, 4, 5]
  1. flat_map
# 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]

test

Test 1

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

Test code
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

Test 2

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
Test code
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

Conclusion

At depth 1

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

When you want to make everything flat at a depth of 2 or more

values.flatten is faster, but it's similar to each_value + flatten.

Execution environment Ruby 2.7.1

Recommended Posts

Speed comparison when the value side of Hash wants to retrieve all with array
How to retrieve the hash value in an array in Ruby
[Ruby] How to retrieve the contents of a double hash
Try to imitate the idea of a two-dimensional array with a one-dimensional array
How to display 0 on the left side of the standard input value
How to output the value when there is an array in the array
The story of toString () starting with passing an array to System.out.println
[Ruby] I want to extract only the value of the hash and only the key
How to convert an array of Strings to an array of objects with the Stream API
I tried to measure and compare the speed of GraalVM with JMH
After all I wanted to preview the contents of mysql with Docker ...
[Note] [Beginner] How to write when changing the value of an array element in a Ruby iterative statement
What I tried when I wanted to get all the fields of a bean
Initialize Ruby array with 0 like Java, that is, set the default value to 0
Pay attention to the boundary check of the input value when using the float type
Specify the default value with @Builder of Lombok
How to find the total value, average value, etc. of a two-dimensional array (multidimensional array)-java
How to request by passing an array to the query with HTTP Client of Ruby
[ruby] How to assign a value to a hash by referring to the value and key of another hash
Summary of how to use the proxy set in IE when connecting with Java
List the contents of categories created with Active Hash
When the hover of Eclipse is hard to see
Speed comparison at the time of generation at the time of date conversion
Convert the array of errors.full_messages to characters and output
[Java] How to get the maximum value of HashMap
Null value is entered when assigning to an array
How to specify an array in the return value / argument of the method in the CORBA IDL file
Whether to make the server side at the time of system rebuild with Kotlin or Java