Skip to content
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

Add Hash#values_at vs Array#map { Hash#[] } comparison #174

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

kewlar
Copy link

@kewlar kewlar commented Mar 14, 2019

No description provided.

@kewlar
Copy link
Author

kewlar commented Mar 14, 2019

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.

@Arcovion
Copy link
Collaborator

This is faster than slice on my machine and returns the same as values_at:

KEYS.map{ |key| HASH[key] }

@kewlar
Copy link
Author

kewlar commented Mar 14, 2019

@Arcovion, cool! Will add it to the benchmark, too. Thanks!

@kewlar
Copy link
Author

kewlar commented Mar 21, 2019

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?

@etagwerker
Copy link
Member

@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.

@kewlar kewlar changed the title Add Hash#values_at vs Hash#slice#values comparison Add Hash#values_at vs Array#map { Hash#[] } comparison Mar 2, 2023
@kewlar
Copy link
Author

kewlar commented Mar 2, 2023

@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?

d: 'qux'
}.freeze

# Some of the keys may not exist in the hash; we want to keep the default values.
Copy link
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: 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants