Создание ruby вложенного ha sh с массивом в качестве внутреннего значения - PullRequest
7 голосов
/ 13 июля 2020

Я пытаюсь создать вложенный ha sh, где внутренние значения представляют собой массивы. Например,

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

Я пробовал

h = Hash.new( |hash, key| hash[key] = Hash.new([]) }

Когда я пробую

h["monday"]["morning"].append("Ben")

и смотрю на h, я получаю

{"monday" => {}}

а не

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

Я новичок в Ruby, есть ли предложения по получению нужной мне функциональности?

Ответы [ 4 ]

7 голосов
/ 13 июля 2020

Закройте, вам нужно будет инициализировать новый ha sh как значение начального ключа и установить массив как значение вложенного ha sh:

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

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

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

Это Таким образом, вам не придется инициализировать массив каждый раз, когда вы хотите получить sh значение. Ключ будет таким, как вы установили в начальном параметре, второй параметр создаст вложенный ha sh, где значением будет массив, который вы можете использовать sh с помощью '<<'. Это решение для использования в реальном коде? Нет, это не очень удобно для чтения, но объясняет способ создания объектов данных в соответствии с вашими потребностями. </p>

6 голосов
/ 13 июля 2020

Рефакторинг для обеспечения явности

Хотя можно создать вложенный инициализатор, используя синтаксис блока Hash # new , он не очень удобочитаем и (как вы видели) может быть трудно отлаживать. Поэтому может быть более полезно построить вложенный ha sh в несколько этапов, которые вы можете проверять и отлаживать, как go.

Кроме того, вы заранее знаете, какими будут ваши ключи: дни недели и утренние / дневные смены. Для этого варианта использования вы могли бы создать их заранее, а не полагаться на значения по умолчанию.

Учтите следующее:

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

Мне это кажется более явным и понятным, но, по общему признанию, субъективно. Между тем, вызов pp schedule покажет вам новую структуру данных:

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

Затем новой структуре данных могут быть присвоены значения вложенного массива, как вы в настоящее время ожидаете:

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

Как дальнейшее уточнение, вы можете добавлять к своим вложенным массивам способом, который гарантирует, что вы не дублируете имена в пределах запланированной смены. Например:

schedule["monday"]["morning"].<<("Ben").uniq!
schedule["monday"]
#=> {"morning"=>["Ben"], "afternoon"=>[]}
3 голосов
/ 14 июля 2020

Есть много способов создать ха sh. Один простой способ состоит в следующем.

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=>[]}}

Заполнение ha sh, конечно, будет зависеть от формата данных. Например, если бы данные были следующими:

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]}

, мы могли бы построить ha sh следующим образом.

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"]
  #     }
  #   }
0 голосов
/ 13 июля 2020

Согласно вашему выше заданному вопросу

h = Hash.new{ |hash, key| hash[key] = Hash.new([]) }

вы пробовали

h["monday"]["morning"].append("Ben")

вместо этого вы должны сначала инициализировать это с помощью массива, а затем вы можете использовать функции массива, такие как append

h["monday"]["morning"] = []
h["monday"]["morning"].append("Ben")

Это будет работать нормально, и вы получите желаемый результат.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...