SamTalks
SamTalks

Reputation: 283

Nested hash iteration: How to iterate a merge over an ( (array of hashes) within a hash )

I'm trying to do as the title says. Here is my code:

school.each { |x| school[:students][x].merge!(semester:"Summer") }

I think I pinpointed the problem to the "[x]" above. If I substitute an array position such as "[2]" it works fine. How can make the iteration work?

If the info above is not enough or you'd like to offer a better solution, please see the details below. Thanks!


The error message I get:

file.rb:31:in []': no implicit conversion of Array into Integer (TypeError) from file.rb:31:inblock in ' from file.rb:31:in each' from file.rb:31:in'

The nested hash below before alteration:

school = { 
  :name => "Happy Funtime School",
  :location => "NYC",
  :instructors => [ 
    {:name=>"Blake", :subject=>"being awesome" },
    {:name=>"Ashley", :subject=>"being better than blake"},
    {:name=>"Jeff", :subject=>"karaoke"}
  ],
  :students => [ 
    {:name => "Marissa", :grade => "B"},
    {:name=>"Billy", :grade => "F"},
    {:name => "Frank", :grade => "A"},
    {:name => "Sophie", :grade => "C"}
  ]
}

I'm trying to append :semester=>"Summer" to each of the last four hashes. Here is what I'm trying to go for:

# ...preceding code is the same. Changed code below...
  :students => [ 
    {:name => "Marissa", :grade => "B", :semester => "Summer"},
    {:name=>"Billy", :grade => "F", :semester => "Summer"},
    {:name => "Frank", :grade => "A", :semester => "Summer"},
    {:name => "Sophie", :grade => "C", :semester => "Summer"}
  ]
}

Upvotes: 2

Views: 915

Answers (3)

Arup Rakshit
Arup Rakshit

Reputation: 118271

I would do as below using Hash#store :

require 'awesome_print'

school = {
                 :name => "Happy Funtime School",
             :location => "NYC",
          :instructors => [
                    {
                                 :name => "Blake",
                              :subject => "being awesome"
                    },
                    {
                                 :name => "Ashley",
                              :subject => "being better than blake"
                    },
                    {
                                 :name => "Jeff",
                              :subject => "karaoke"
                    }
          ],
             :students => [
                    {
                               :name => "Marissa",
                              :grade => "B"
                    },
                    {
                               :name => "Billy",
                              :grade => "F"
                    },
                    {
                               :name => "Frank",
                              :grade => "A"
                    },
                    {
                               :name => "Sophie",
                              :grade => "C"
                    }
          ]
}

school[:students].each{|h| h.store(:semester ,"Summer")}
ap school,:index => false,:indent => 10

output

{
                 :name => "Happy Funtime School",
             :location => "NYC",
          :instructors => [
                    {
                                 :name => "Blake",
                              :subject => "being awesome"
                    },
                    {
                                 :name => "Ashley",
                              :subject => "being better than blake"
                    },
                    {
                                 :name => "Jeff",
                              :subject => "karaoke"
                    }
          ],
             :students => [
                    {
                                  :name => "Marissa",
                                 :grade => "B",
                              :semester => "Summer"
                    },
                    {
                                  :name => "Billy",
                                 :grade => "F",
                              :semester => "Summer"
                    },
                    {
                                  :name => "Frank",
                                 :grade => "A",
                              :semester => "Summer"
                    },
                    {
                                  :name => "Sophie",
                                 :grade => "C",
                              :semester => "Summer"
                    }
          ]
}

Upvotes: 0

Idrees Khan
Idrees Khan

Reputation: 107

The issue is that when you do array.each {|x| do something}, x actually refers to each element in the array.

For example, in the first iteration of the loop,

x = {:name => "Marissa", :grade => "B"}

So what you are really doing is trying to reference:

school[:student][{:name => "Marissa", :grade => "B"}]

Which will not work

What you could do instead is create a for loop to track the index.

for i in 0 ... school[:student].count
    school[:students][i].merge!(semester:"Summer")
end

Edit: Stefan's solution is much better than mine, but I will leave this up to show where you went wrong.

Upvotes: 0

Stefan
Stefan

Reputation: 114158

Just iterate over the students:

school[:students].each { |student| student[:semester] = "Summer" }

Or, using merge:

school[:students].each { |student| student.merge!(semester: "Summer") }

Upvotes: 1

Related Questions