Search code examples
ruby-on-railsrubyruby-hash

Combine 2 hashes with the same key


I am wanting to combine 2 hashes that have the same keys.

@clean_by_hour = Sale.where(item_name: clean).group_by_hour_of_day(:complete_time, format: "%-l %P").count
=> {"12 am"=>0, "1 am"=>0, "2 am"=>0, "3 am"=>0, "4 am"=>0, "5 am"=>0, "6 am"=>0, "7 am"=>0, "8 am"=>4, "9 am"=>14, "10 am"=>19, "11 am"=>10, "12 pm"=>19, "1 pm"=>16, "2 pm"=>13, "3 pm"=>18, "4 pm"=>7, "5 pm"=>4, "6 pm"=>4, "7 pm"=>0, "8 pm"=>0, "9 pm"=>0, "10 pm"=>0, "11 pm"=>0}

@lube_by_hour = Sale.where(item_name: lube).group_by_hour_of_day(:complete_time, format: "%-l %P").count

=> {"12 am"=>0, "1 am"=>0, "2 am"=>0, "3 am"=>0, "4 am"=>0, "5 am"=>0, "6 am"=>0, "7 am"=>0, "8 am"=>3, "9 am"=>4, "10 am"=>10, "11 am"=>14, "12 pm"=>10, "1 pm"=>8, "2 pm"=>5, "3 pm"=>20, "4 pm"=>4, "5 pm"=>2, "6 pm"=>0, "7 pm"=>0, "8 pm"=>0, "9 pm"=>0, "10 pm"=>0, "11 pm"=>0}

I am wanting the new hash to look like:

{"12 am"=> 0, 0}

At least that is what I think I want. I am attempting to combine the 2 hashes so that I can display the data in a table.

I know I will need to alter this code, but this is what I am working with right now in the view.

    <% @clean_by_hour.each do |hour, count| %>
    
    <% if count != 0 %>
      <tr>
        <td><%= hour %></td>
        <td><%= count %></td>
      <% end %>
    <% end %>
    <% @lube_by_hour.each do |hour, count| %>
    <% if count != 0 %>
      <td><%= count %></td>
     <% end %>
    <% end %>
      </tr>

Thank you!


Solution

  • First, I think by {"12 am"=> 0, 0} you mean a Hash with each of its keys being an hour and each value an Array with two elements, one representing the number of cleans in that hour and the other the number of lubes. If that's the case it should be like this: {"12 am"=> [0, 0]} (with [ and ] around each value)

    You can do that with something like this:

    @count_by_hour = @clean_by_hour.keys.each_with_object({}) do |k, h|
      h[k] = [@clean_by_hour[k], @lube_by_hour[k]]
    end
    
    @count_by_hour # =>
    {"12 am"=>[0, 0],
     "1 am"=>[0, 0],
     "2 am"=>[0, 0],
     "3 am"=>[0, 0],
     "4 am"=>[0, 0],
     "5 am"=>[0, 0],
     "6 am"=>[0, 0],
     "7 am"=>[0, 0],
     "8 am"=>[4, 3],
     "9 am"=>[14, 4],
     "10 am"=>[19, 10],
     "11 am"=>[10, 14],
     "12 pm"=>[19, 10],
     "1 pm"=>[16, 8],
     "2 pm"=>[13, 5],
     "3 pm"=>[18, 20],
     "4 pm"=>[7, 4],
     "5 pm"=>[4, 2],
     "6 pm"=>[4, 0],
     "7 pm"=>[0, 0],
     "8 pm"=>[0, 0],
     "9 pm"=>[0, 0],
     "10 pm"=>[0, 0],
     "11 pm"=>[0, 0]}
    

    You could also use a Hash for each value to improve the readability and prevent bugs: (It's easier to remember which Hash key to use than which Array index.)

    @count_by_hour = @clean_by_hour.keys.each_with_object({}) do |k, h|
      h[k] = { clean: @clean_by_hour[k], lube: @lube_by_hour[k] }
    end
    
    @count_by_hour # =>
    {"12 am"=>{:clean=>0, :lube=>0},
     "1 am"=>{:clean=>0, :lube=>0},
     "2 am"=>{:clean=>0, :lube=>0},
     "3 am"=>{:clean=>0, :lube=>0},
     "4 am"=>{:clean=>0, :lube=>0},
     "5 am"=>{:clean=>0, :lube=>0},
     "6 am"=>{:clean=>0, :lube=>0},
     "7 am"=>{:clean=>0, :lube=>0},
     "8 am"=>{:clean=>4, :lube=>3},
     "9 am"=>{:clean=>14, :lube=>4},
     "10 am"=>{:clean=>19, :lube=>10},
     "11 am"=>{:clean=>10, :lube=>14},
     "12 pm"=>{:clean=>19, :lube=>10},
     "1 pm"=>{:clean=>16, :lube=>8},
     "2 pm"=>{:clean=>13, :lube=>5},
     "3 pm"=>{:clean=>18, :lube=>20},
     "4 pm"=>{:clean=>7, :lube=>4},
     "5 pm"=>{:clean=>4, :lube=>2},
     "6 pm"=>{:clean=>4, :lube=>0},
     "7 pm"=>{:clean=>0, :lube=>0},
     "8 pm"=>{:clean=>0, :lube=>0},
     "9 pm"=>{:clean=>0, :lube=>0},
     "10 pm"=>{:clean=>0, :lube=>0},
     "11 pm"=>{:clean=>0, :lube=>0}}