Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -1038,6 +1038,26 @@ Array#each_w/_object: 1352851.8 i/s - 1.88x slower
Hash#select-include : 760944.2 i/s - 3.34x 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 3.2.1 (2023-02-08 revision 31819e82c8) [x86_64-darwin22]
Warming up --------------------------------------
Hash#values_at 503.783k i/100ms
Array#map { Hash#[] } 279.576k i/100ms
Calculating -------------------------------------
Hash#values_at 4.901M (± 4.1%) i/s - 24.685M in 5.046090s
Array#map { Hash#[] } 2.801M (± 3.1%) i/s - 14.258M in 5.095692s

Comparison:
Hash#values_at : 4900567.9 i/s
Array#map { Hash#[] }: 2800981.4 i/s - 1.75x slower
```

### Proc & Block

Expand Down
25 changes: 25 additions & 0 deletions code/hash/values_at-vs-map.rb
Original file line numberDiff line numberDiff 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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For existing keys, the benchmark does not change much.

# frozen_string_literal: truerequire'benchmark/ips'HASH={a: 'foo',b: 'bar',c: 'baz',d: 'qux'}.freeze# the keys exist in the hashKEYS=%i[abcd].freezedeffastestHASH.values_at(*KEYS)enddefslowHASH.fetch_values(*KEYS)enddefslowestKEYS.map{ |key| HASH[key]}endBenchmark.ipsdo |x|
x.report('Hash#values_at '){fastest}x.report('Hash#fetch_values '){slow}x.report('Array#map { Hash#[] }'){slowest}x.compare!end
ydakuka@yauhenid:~/ruby-docker-app$ docker run ruby-app Warming up --------------------------------------Hash#values_at  405.669k i/100msHash#fetch_values  354.263k i/100msArray#map { Hash#[] } 221.960k i/100msCalculating -------------------------------------Hash#values_at  4.191M (± 4.7%) i/s - 21.095M in 5.045130sHash#fetch_values  3.895M (± 6.8%) i/s - 19.484M in 5.031663sArray#map { Hash#[] } 2.429M (± 6.1%) i/s - 12.208M in 5.048470sComparison:Hash#values_at : 4190993.6 i/sHash#fetch_values : 3894866.5 i/s - same-ish: difference falls within errorArray#map { Hash#[] }: 2429428.6 i/s - 1.73x slower

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