🗂
[Feature #16993] Hash#keys から Set を生成する Hash#keys_to_set メソッドを追加する提案
[Feature #16993] Sets: from hash keys using Hash#key_set
- 現状
Hash
のキーからSet
のオブジェクトを生成する場合、以下のようにコードを書く必要がある
h = { a: 1, b: 2, c: 3 }
pp Set.new(h.keys)
# => #<Set: {:a, :b, :c}>
- このときに
Hash#keys
を呼び出すコストがあるので、それを軽減するために以下のようなHash#key_set
メソッドを追加する提案- 一時的に配列を作成したり、キーをすべて再ハッシュする必要がある、と書いてありますね
h = { a: 1, b: 2, c: 3 }
pp h.key_set
# => #<Set: {:a, :b, :c}>
- 要は
Set.new(h.keys)
を行う専用のメソッドを追加したい、って話みたいですね -
Set
あんまり使わないんですがこういうコードって結構書いたりするんですかね? - パフォーマンスに関しては以下のようなベンチマークが提示されています
# frozen_string_literal: true
require 'set'
require 'benchmark/ips'
class Hash
def key_set
s = Set.new
s.instance_variable_set(:@hash, transform_values { true })
s
end
end
size = 50
h = (1..size).to_h { |i| ['x' * i, nil] }
Benchmark.ips do |x|
x.report("key_set") { h.key_set }
x.report("keys") { Set.new(h.keys) }
x.report("new(each_key)") { Set.new(h.each_key) }
x.report("each_key{}") { h2 = {}; h.each_key {|k| h2[k] = true} ; h2 }
Calculating -------------------------------------
key_set 244.549k (± 7.4%) i/s - 1.219M in 5.017876s
keys 82.661k (± 2.3%) i/s - 417.400k in 5.052408s
new(each_key) 75.002k (± 5.0%) i/s - 377.400k in 5.045102s
each_key{} 114.757k (± 3.8%) i/s - 582.000k in 5.079700s
- チケットが起票されたのは4年前なんですが最近これを追加する PR が投げられてました
- [Feature #16993] Introduce Hash#keys_to_set by grzegorz-jakubiak · Pull Request #40 · ruby/set
- 実装的には
set
の方にモンキーパッチを当てているみたいですね - あと名前がより自明な
Hash#keys_to_set
という名前にかわっています
Discussion