mirror of https://github.com/rails/rails
Optimize Hash#stringify_keys
Using Symbol#name allows to hit two birds with one stone. First it will return a pre-existing string, so will save one allocation per key. Second, that string will be already interned, so it will save the internal `Hash` implementation the work of looking up the interned strings table to deduplicate the key. ``` ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-darwin21] Warming up -------------------------------------- to_s 17.768k i/100ms cond 23.703k i/100ms Calculating ------------------------------------- to_s 169.830k (±10.4%) i/s - 852.864k in 5.088377s cond 236.803k (± 7.9%) i/s - 1.185M in 5.040945s Comparison: to_s: 169830.3 i/s cond: 236803.4 i/s - 1.39x faster ``` ```ruby require 'bundler/inline' gemfile do source 'https://rubygems.org' gem 'benchmark-ips', require: false end HASH = { first_name: nil, last_name: nil, country: nil, profession: nil, language: nil, hobby: nil, pet: nil, longer_name: nil, occupation: nil, mailing_address: nil, }.freeze require 'benchmark/ips' Benchmark.ips do |x| x.report("to_s") { HASH.transform_keys(&:to_s) } x.report("cond") { HASH.transform_keys { |k| Symbol === k ? k.name : k.to_s } } x.compare!(order: :baseline) end ```
This commit is contained in:
parent
0b04c15147
commit
8c7e69b79b
|
@ -8,13 +8,13 @@ class Hash
|
|||
# hash.stringify_keys
|
||||
# # => {"name"=>"Rob", "age"=>"28"}
|
||||
def stringify_keys
|
||||
transform_keys(&:to_s)
|
||||
transform_keys { |k| Symbol === k ? k.name : k.to_s }
|
||||
end
|
||||
|
||||
# Destructively converts all keys to strings. Same as
|
||||
# +stringify_keys+, but modifies +self+.
|
||||
def stringify_keys!
|
||||
transform_keys!(&:to_s)
|
||||
transform_keys! { |k| Symbol === k ? k.name : k.to_s }
|
||||
end
|
||||
|
||||
# Returns a new hash with all keys converted to symbols, as long as
|
||||
|
@ -82,14 +82,14 @@ class Hash
|
|||
# hash.deep_stringify_keys
|
||||
# # => {"person"=>{"name"=>"Rob", "age"=>"28"}}
|
||||
def deep_stringify_keys
|
||||
deep_transform_keys(&:to_s)
|
||||
deep_transform_keys { |k| Symbol === k ? k.name : k.to_s }
|
||||
end
|
||||
|
||||
# Destructively converts all keys to strings.
|
||||
# This includes the keys from the root hash and from all
|
||||
# nested hashes and arrays.
|
||||
def deep_stringify_keys!
|
||||
deep_transform_keys!(&:to_s)
|
||||
deep_transform_keys! { |k| Symbol === k ? k.name : k.to_s }
|
||||
end
|
||||
|
||||
# Returns a new hash with all keys converted to symbols, as long as
|
||||
|
|
|
@ -393,7 +393,7 @@ module ActiveSupport
|
|||
|
||||
private
|
||||
def convert_key(key)
|
||||
key.kind_of?(Symbol) ? key.name : key
|
||||
Symbol === key ? key.name : key
|
||||
end
|
||||
|
||||
def convert_value(value, conversion: nil)
|
||||
|
|
|
@ -76,7 +76,13 @@ module ActiveSupport
|
|||
when Hash
|
||||
result = {}
|
||||
value.each do |k, v|
|
||||
k = k.to_s unless String === k
|
||||
unless String === k
|
||||
k = if Symbol === k
|
||||
k.name
|
||||
else
|
||||
k.to_s
|
||||
end
|
||||
end
|
||||
result[k] = jsonify(v)
|
||||
end
|
||||
result
|
||||
|
|
Loading…
Reference in New Issue