When we want to set value in nested Hash the code become longer, I’d like to have similar to Hash#dig
but for setting values
example:
users_hash = {}
users.each do |user|
country_code = user.country&.code
users_hash[country_code] ||= {}
users_hash[country_code][user.city] ||= {}
users_hash[country_code][user.city][user.email] = user
end
With Hash#deep_set (or other better name) it could be
users_hash = {}
users.each do |user|
users_hash.deep_set(
[user.country&.code, user.city, user.email] => user
)
# or
users_hash.deep_set(user.country&.code, user.city, user.email, with: user)
#
users_hash.deep_hash(user.country&.code, user.city)[user.email] = user
# or
users_hash.deep_set_array(user.country&.code, user.city, with: user)
end
Also, can override :[]=
method to support multiple arguments
...
def []=(*args, **kargs)
# make deep set
end
...
users_hash = HashWithDeepSet.new # or {}.with_deep_set
users.each do |user|
users_hash[user.country&.code, user.city, user.email] = user
# or
users_hash[user.country&.code, user.city, fill_with: []] << user
end
some other useful methods I copy from project to project, mostly for large arrays to make lookup faster
def map_by_key(array, key)
result = {}
array.each do |element|
result[element[key]] ||= []
result[element[key]] << element
end
result
end
def uniq_map_by_key(array, key)
result = {}
array.each do |element|
result[element[key]] = element
end
result
end