次の配列があったとして、
a = [:c, :b, :c, :c, :a, :b]
要素とその個数をペアにしたハッシュを求めるコードが試行錯誤ののちにだんだん読みやすくなっていく例です。(※主観です)
h = {}; a.each { |e| h[e] = a.count(e) }; h # => {:c=>3, :b=>2, :a=>1}
h = {}; a.each { |e| h[e] ||= a.count(e) }; h # => {:c=>3, :b=>2, :a=>1}
h = {}; a.uniq.each { |e| h[e] = a.count(e) }; h # => {:c=>3, :b=>2, :a=>1}
h = {}; a.each {|e| h[e] = (h[e] || 0) + 1 }; h # => {:c=>3, :b=>2, :a=>1}
h = {}; a.each {|e| h[e] = h.fetch(e, 0) + 1 }; h # => {:c=>3, :b=>2, :a=>1}
h = {}; a.each {|e| h[e] = h.fetch(e) { 0 } + 1 }; h # => {:c=>3, :b=>2, :a=>1}
h = {}; a.each {|e| h[e] = h[e].to_i.next }; h # => {:c=>3, :b=>2, :a=>1}
h = Hash.new(0); a.each { |e| h[e] += 1 }; h # => {:c=>3, :b=>2, :a=>1}
Hash.new(0).tap { |h| a.each { |e| h[e] += 1 } } # => {:c=>3, :b=>2, :a=>1}
Hash[*a.flat_map { |e| [e, a.count(e)] }] # => {:c=>3, :b=>2, :a=>1}
a.zip(a.collect { |e| a.count(e) }).to_h # => {:c=>3, :b=>2, :a=>1}
a.map { |e| [e, a.count(e)] }.to_h # => {:c=>3, :b=>2, :a=>1}
a.uniq.map { |e| [e, a.count(e)] }.to_h # => {:c=>3, :b=>2, :a=>1}
a.each_with_object(Hash.new(0)) { |e, m| m[e] += 1 } # => {:c=>3, :b=>2, :a=>1}
a.each_with_object({}) { |e, m| m[e] = (m[e] || 0) + 1 } # => {:c=>3, :b=>2, :a=>1}
a.inject(Hash.new(0)) { |a, e| a[e] += 1; a } # => {:c=>3, :b=>2, :a=>1}
a.inject(Hash.new(0)) { |a, e| a.tap { |a| a[e] += 1 } } # => {:c=>3, :b=>2, :a=>1}
a.inject({}){|a, e| a.merge(e => 1) { |_, a, b| a + b } } # => {:c=>3, :b=>2, :a=>1}
a.group_by{|e|e}.collect { |k, v| [k, v.count] }.to_h # => {:c=>3, :b=>2, :a=>1}
a.group_by{|e|e}.inject({}){|a,(k,v)|a.merge(k => v.size)} # => {:c=>3, :b=>2, :a=>1}
a.group_by{|e|e}.transform_values { |e| e.size } # => {:c=>3, :b=>2, :a=>1}
a.group_by(&:itself).transform_values(&:size) # => {:c=>3, :b=>2, :a=>1}
a.tally # => {:c=>3, :b=>2, :a=>1}
ついでにそれぞれの速度は次のようになりました。
RUBY_VERSION # => "2.7.0"
require "active_support/core_ext/benchmark"
def _; "%7.2f ms" % Benchmark.ms { 50_0000.times { yield } } end
_ { h = {}; a.each { |e| h[e] = a.count(e) }; h } # => " 528.82 ms"
_ { h = {}; a.each { |e| h[e] ||= a.count(e) }; h } # => " 437.72 ms"
_ { h = {}; a.uniq.each { |e| h[e] = a.count(e) }; h } # => " 408.69 ms"
_ { h = {}; a.each {|e| h[e] = (h[e] || 0) + 1 }; h } # => " 371.57 ms"
_ { h = {}; a.each {|e| h[e] = h.fetch(e, 0) + 1 }; h } # => " 412.14 ms"
_ { h = {}; a.each {|e| h[e] = h.fetch(e) { 0 } + 1 }; h } # => " 475.63 ms"
_ { h = {}; a.each {|e| h[e] = h[e].to_i.next }; h } # => " 529.86 ms"
_ { h = Hash.new(0); a.each { |e| h[e] += 1 }; h } # => " 418.89 ms"
_ { Hash.new(0).tap { |h| a.each { |e| h[e] += 1 } } } # => " 452.42 ms"
_ { Hash[*a.flat_map { |e| [e, a.count(e)] }] } # => " 835.85 ms"
_ { a.zip(a.collect { |e| a.count(e) }).to_h } # => " 934.52 ms"
_ { a.map { |e| [e, a.count(e)] }.to_h } # => " 685.76 ms"
_ { a.uniq.map { |e| [e, a.count(e)] }.to_h } # => " 510.16 ms"
_ { a.each_with_object(Hash.new(0)) { |e, m| m[e] += 1 } } # => " 503.50 ms"
_ { a.each_with_object({}) { |e, m| m[e] = (m[e] || 0) + 1 } } # => " 452.22 ms"
_ { a.inject(Hash.new(0)) { |a, e| a[e] += 1; a } } # => " 522.28 ms"
_ { a.inject(Hash.new(0)) { |a, e| a.tap { |a| a[e] += 1 } } } # => " 761.82 ms"
_ { a.inject({}){|a, e| a.merge(e => 1) { |_, a, b| a + b } } } # => "1017.48 ms"
_ { a.group_by{|e|e}.collect { |k, v| [k, v.count] }.to_h } # => " 866.90 ms"
_ { a.group_by{|e|e}.inject({}){|a,(k,v)|a.merge(k => v.size)} } # => "1075.56 ms"
_ { a.group_by{|e|e}.transform_values { |e| e.size } } # => " 541.91 ms"
_ { a.group_by(&:itself).transform_values(&:size) } # => " 689.96 ms"
_ { a.tally } # => " 260.09 ms"
バージョン毎の速度比較
2.4.1 | 2.6.5 | 2.7.0 |
---|---|---|
1034.64 | 487.52 | 528.82 |
826.21 | 421.96 | 437.72 |
950.99 | 382.07 | 408.69 |
580.79 | 366.15 | 371.57 |
626.53 | 393.59 | 412.14 |
697.68 | 451.79 | 475.63 |
694.42 | 494.54 | 529.86 |
617.90 | 395.69 | 418.89 |
644.93 | 417.29 | 452.42 |
1406.28 | 764.19 | 835.85 |
1499.53 | 907.43 | 934.52 |
1238.92 | 652.00 | 685.76 |
1006.41 | 490.25 | 510.16 |
724.30 | 472.74 | 503.50 |
686.70 | 451.96 | 452.22 |
733.23 | 477.62 | 522.28 |
944.87 | 667.43 | 761.82 |
4706.51 | 889.69 | 1017.48 |
1290.49 | 772.25 | 866.90 |
3063.37 | 953.74 | 1075.56 |
1016.31 | 551.76 | 541.91 |
1021.88 | 607.18 | 689.96 |
260.09 |