• Register
31,120 points
10 6 4

Solution:

First thing first, you'll have to initialise a new hash as the value of the initial key, and put an Array as the value of the nested hash:

Follw the below code:

h = Hash.new { |hash, key| hash[key] = Hash.new { |k, v| k[v] = Array.new } }

h["monday"]["morning"] << "Ben"

{"monday"=>{"morning"=>["Ben"]}} 

This method you will not have to initialise an array each time you want to push a value. The key will be as you fix in the initial parameter, the second parameter will make a nested hash where the value will be an array you can push to with '<<'. Is this a solution to use in live code? No, it’s not very readable however illustrates a system of forming data objects to fit your needs.

For example – like this below program

require 'date'

# initialize your hash with a literal
schedule = {}

# use constant from Date module to initialize your
# lowercase keys
Date::DAYNAMES.each do |day|
    # create keys with empty arrays for each shift
    schedule[day.downcase] = { 
      "morning"   => [], 
      "afternoon" => [], 
    }   
end

This appears more obvious and readable to me, however that's admittedly subjective. In the meanwhile, calling pp schedule will guide you the new data structure:

{"sunday"=>{"morning"=>[], "afternoon"=>[]},
 "monday"=>{"morning"=>[], "afternoon"=>[]},
 "tuesday"=>{"morning"=>[], "afternoon"=>[]},
 "wednesday"=>{"morning"=>[], "afternoon"=>[]},
 "thursday"=>{"morning"=>[], "afternoon"=>[]},
 "friday"=>{"morning"=>[], "afternoon"=>[]},
 "saturday"=>{"morning"=>[], "afternoon"=>[]}}

The new data structure can then have its nested array values assigned as you presently expect:

schedule["monday"]["morning"].append("Ben")
#=> ["Ben"]

As a more scour, you could append to your nested arrays in a system that make sures you don't duplicate names inside a scheduled shift. Follwing this

schedule["monday"]["morning"].<<("Ben").uniq!
schedule["monday"]
#=> {"morning"=>["Ben"], "afternoon"=>[]}

Or, You can follw this method

Code:

days      = [:monday,  :tuesday]
day_parts = [:morning, :afternoon]

h = days.each_with_object({}) do |d,h|
  h[d] = day_parts.each_with_object({}) { |dp,g| g[dp] = [] }
end
  #=> {:monday=>{:morning=>[], :afternoon=>[]},
  #    :tuesday=>{:morning=>[], :afternoon=>[]}}

Populating the hash will of course rely on the format of the data. As example, in case the data were as follows:

people = { "John"   =>[:monday,  :morning],
           "Katie"  =>[:monday,  :morning],
           "Dave"   =>[:monday,  :morning],
           "Anne"   =>[:monday,  :afternoon],
           "Charlie"=>[:monday,  :afternoon],
           "Joe"    =>[:tuesday, :morning],
           "Chris"  =>[:tuesday, :afternoon],
           "Tim"    =>[:tuesday, :afternoon],
           "Melissa"=>[:tuesday, :afternoon]}

Even we could build the hash this way as follws:

people.each { |name,(day,day_part)| h[day][day_part] << name }
  #=> {
  #     :monday=>{
  #       :morning=>["John", "Katie", "Dave"],
  #       :afternoon=>["Anne", "Charlie"]
  #     },
  #     :tuesday=>{
  #       :morning=>["Joe"],
  #       :afternoon=>["Chris", "Tim", "Melissa"]
  #     }
  #   }

 

31,120 points
10 6 4