[RUBY] Comparaison de vitesse lorsque le côté valeur de Hash veut tout récupérer avec un tableau

TL;DR Le côté valeur est

--Profondeur 1 La vitesse la plus rapide est each_value Si vous voulez continuer la chaîne de méthodes, vous pouvez penser à flat_map

Environnement d'exécution Ruby 2.7.1

modèle

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) } #L'exemple ci-dessus convient également avec push au lieu de 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.Si c'est 7,
sample.flat_map { _2 }
# =>  [1, 2, 3, 2, 3, 4, 3, 4, 5]

# _Si 2 ne peut pas être utilisé
sample.flat_map { |_, v| v }
# =>  [1, 2, 3, 2, 3, 4, 3, 4, 5]

# flat_Si vous voulez montrer ici quelle est la valeur du récepteur de la carte, je pense que ce peut être une bonne idée de l'écrire.
sample.flat_map { |_, number_ary| number_ary }
# =>  [1, 2, 3, 2, 3, 4, 3, 4, 5]

tester

Test 1

Lorsque vous souhaitez récupérer la valeur de la profondeur 1 sous la forme d'un tableau plat

Les résultats sont les suivants. (Comme c'est le nombre de fois que la boucle peut être tournée par seconde, la grande est plus rapide)

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

<détails>

Code de test </ summary>

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

Lorsque vous voulez tout aplatir à une profondeur de 2 et le retirer

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

<détails>

Code de test </ summary>

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

En profondeur 1

C'est le plus rapide à faire avec each_value. (Ce n'est pas très différent de l'utilisation de chacun, mais c'est généralement each_value compte tenu de la lisibilité) Si c'est flat_map, la valeur de retour sera la valeur souhaitée et il est facile de continuer la chaîne de méthodes, mais il est tard values.flatten est assez lent

Lorsque vous voulez que tout soit plat à une profondeur de 2 ou plus

values.flatten est plus rapide, mais il est similaire à each_value + flatten.

Environnement d'exécution Ruby 2.7.1

Recommended Posts