Issue #16993 has been updated by marcandre (Marc-Andre Lafortune).


sawa (Tsuyoshi Sawada) wrote in #note-2:
> Would
> =

> ```ruby
> Set.new(h.each_key)
> ```
> =

> not work?

It will definitely work, but it will be the same as `Set.new(h.keys)` (a bi=
t slower because enumerator is a bit slow). It still iterates on the keys, =
and add them to the new hash.

Here's a comparison:

```
# frozen_string_literal: true
require 'set'
require 'benchmark/ips'

class Hash
  def key_set
    s =3D Set.new
    s.instance_variable_set(:@hash, transform_values { true })
    s
  end
end

size =3D 50
h =3D (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 =3D {}; h.each_key {|k| h2[k] =3D true}=
 ; h2  }
```

The last example builds a Hash, not a Set, but it is to show that you can n=
ot be quicker than that if you rehash the keys.
I get these results:

```
Calculating -------------------------------------
             key_set    244.549k (=B1 7.4%) i/s -      1.219M in   5.017876s
                keys     82.661k (=B1 2.3%) i/s -    417.400k in   5.052408s
       new(each_key)     75.002k (=B1 5.0%) i/s -    377.400k in   5.045102s
          each_key{}    114.757k (=B1 3.8%) i/s -    582.000k in   5.079700s
```

If you increase the `size`, the ratio will be bigger.
A builtin `keyset` would be even faster, since it would avoid calling the b=
lock `{ true }`; yielding is not super fast in Ruby.

----------------------------------------
Feature #16993: Sets: from hash keys using Hash#key_set
https://bugs.ruby-lang.org/issues/16993#change-86358

* Author: marcandre (Marc-Andre Lafortune)
* Status: Open
* Priority: Normal
----------------------------------------
To create a set from hash keys currently implies a temporary array for all =
keys, rehashing all those keys and rebuilding a hash. Instead, the hash cou=
ld be copied and its values set to `true`.

```ruby
h =3D {a: 1}
# Now:
Set.new(h.keys) # =3D> Set[:a]
# After
h.key_set # =3D> Set[:a], efficiently.
```




-- =

https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=3Dunsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>