Skip to content

Commit

Permalink
Added: other methods of slicing Hash values, when keys may not exist.
Browse files Browse the repository at this point in the history
  • Loading branch information
kewlar committed Mar 1, 2023
1 parent 47e9ce1 commit 2696656
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 0 deletions.
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1061,6 +1061,53 @@ Comparison:
Hash#slice#values: 4817081.6 i/s - 1.57x slower
```

##### `Hash#values_at` vs `Array#map { Hash#[] }`
[code](code/hash/values_at-vs-map.rb)

To select hash values by keys, when some of the keys may not exist in the hash,
and you care about the default values.

```
$ ruby -v code/hash/values_at-vs-map.rb
ruby 2.6.2p47 (2019-03-13 revision 67232) [x86_64-darwin18]
Warming up --------------------------------------
Hash#values_at 245.809k i/100ms
Array#map { Hash#[] } 185.153k i/100ms
Calculating -------------------------------------
Hash#values_at 5.284M (± 3.3%) i/s - 26.547M in 5.030606s
Array#map { Hash#[] } 3.104M (± 2.7%) i/s - 15.553M in 5.014067s
Comparison:
Hash#values_at : 5283787.1 i/s
Array#map { Hash#[] }: 3104255.1 i/s - 1.70x slower
```

##### `Hash#slice#values` vs `Hash#values_at#compact` vs `Array#map { Hash#[] }#compact`
[code](code/hash/values_at-vs-map.rb)

To select hash values by keys, when some of the keys may not exist in the hash,
and you care only about the intersection (i.e. ignore the default values).

NOTE: `#compact`-based methods only work when the default value of `Hash` is
`nil`.

```
$ ruby -v code/hash/values_at-compact-vs-slice-values-vs-map-compact.rb
ruby 2.6.2p47 (2019-03-13 revision 67232) [x86_64-darwin18]
Warming up --------------------------------------
Hash#slice#values 227.519k i/100ms
Hash#values_at#compact 211.820k i/100ms
Array#map#compact 159.760k i/100ms
Calculating -------------------------------------
Hash#slice#values 4.420M (± 1.5%) i/s - 22.297M in 5.046173s
Hash#values_at#compact 3.926M (± 1.6%) i/s - 19.699M in 5.019481s
Array#map#compact 2.508M (± 2.2%) i/s - 12.621M in 5.034508s
Comparison:
Hash#slice#values : 4419599.9 i/s
Hash#values_at#compact: 3925677.1 i/s - 1.13x slower
Array#map#compact : 2508230.2 i/s - 1.76x slower
```

### Proc & Block

Expand Down
31 changes: 31 additions & 0 deletions code/hash/values_at-compact-vs-slice-values-vs-map-compact.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
require 'benchmark/ips'

HASH = {
a: 'foo',
b: 'bar',
c: 'baz',
d: 'qux'
}.freeze

# Some of the keys may not exist in the hash; we don't care about the default values.
KEYS = %i[a c e f].freeze

# NOTE: This is the only correct method, if the default value of Hash may be not nil.
def fast
HASH.slice(*KEYS).values
end

def slow
HASH.values_at(*KEYS).compact
end

def slowest
KEYS.map { |key| HASH[key] }.compact
end

Benchmark.ips do |x|
x.report('Hash#slice#values ') { fast }
x.report('Hash#values_at#compact') { slow }
x.report('Array#map#compact ') { slowest }
x.compare!
end
25 changes: 25 additions & 0 deletions code/hash/values_at-vs-map.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
require 'benchmark/ips'

HASH = {
a: 'foo',
b: 'bar',
c: 'baz',
d: 'qux'
}.freeze

# Some of the keys may not exist in the hash; we want to keep the default values.
KEYS = %i[a c e f].freeze

def fast
HASH.values_at(*KEYS)
end

def slow
KEYS.map { |key| HASH[key] }
end

Benchmark.ips do |x|
x.report('Hash#values_at ') { fast }
x.report('Array#map { Hash#[] }') { slow }
x.compare!
end

0 comments on commit 2696656

Please sign in to comment.