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