proposal: Hash#deep_set

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

This seems to have similarity with this previous proposal. As suggested on that discussion, using the default_proc functionality of Ruby to auto-create nested hashes seems to offer similar benefits without anything new.

As to your map_by_key that seems to be doing the same thing as Ruby built-in group_by function. And your uniq_map_by_key seems like the same as the ActiveSupport’s built-in index_by function.