-
Couldn't load subscription status.
- Fork 378
Add Hash#values_at vs Array#map { Hash#[] } comparison #174
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
DO NOT MERGE YET.
Just noticed that #values_at and #slice#values return different results when Hash members are missing 🤦♂️
Will update the code and the benchmark, and see if it's still worth merging.
This is faster than slice on my machine and returns the same as values_at:
KEYS.map{ |key| HASH[key] }
@Arcovion, cool! Will add it to the benchmark, too. Thanks!
Added more ways of slicing Hash values, and organized them into three separate cases:
- when all keys are expected to exist in the Hash (
Hash#values_at); - when some keys may not exist in the Hash, and we care about the non-existing keys (
Hash#values_at); - when some keys may not exist in the Hash, and we care only about the existing keys (
Hash#slice#values).
Thoughts?
@kewlar I see the value in adding code/hash/values_at-vs-map.rb because it is quite straightforward and natural. But I don't see the value in adding the other benchmarks. The other examples are doing too many things and it is hard to tell which part makes one slower than the other.
I'm happy to add code/hash/values_at-vs-map.rb if you submit just that in this PR or another PR.
137625c to
2696656
Compare
@etagwerker, thanks for the feedback!
You're right, the other benchmarks are really just edge cases, and don't contribute much. And Hash#values_at is the best performing in them anyway.
I've removed the redundant benchmarks. How does it look now?
There was a problem hiding this comment.
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: true require 'benchmark/ips' HASH = { a: 'foo', b: 'bar', c: 'baz', d: 'qux' }.freeze # the keys exist in the hash KEYS = %i[a b c d].freeze def fastest HASH.values_at(*KEYS) end def slow HASH.fetch_values(*KEYS) end def slowest KEYS.map { |key| HASH[key] } end Benchmark.ips do |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/100ms Hash#fetch_values 354.263k i/100ms Array#map { Hash#[] } 221.960k i/100ms Calculating ------------------------------------- Hash#values_at 4.191M (± 4.7%) i/s - 21.095M in 5.045130s Hash#fetch_values 3.895M (± 6.8%) i/s - 19.484M in 5.031663s Array#map { Hash#[] } 2.429M (± 6.1%) i/s - 12.208M in 5.048470s Comparison: Hash#values_at : 4190993.6 i/s Hash#fetch_values : 3894866.5 i/s - same-ish: difference falls within error Array#map { Hash#[] }: 2429428.6 i/s - 1.73x slower
No description provided.