Search code examples
rubyruby-hash

Next key/value pair overwrites the existing pair in a hash while trying to add pair with new key


I have:

fruits = {
  "orange" => {:season => "winter"},
  "apple" => {:season => "winter"},
  "banana" => {:season => "summer"},
  "grape" => {:season => "spring"},
  "peach" => {:season => "winter"},
  "pineapple" => {:season => "summer"}
}

I want to get:

{
  "winter"=>["orange", "apple", "peach"],
  "summer"=>["banana", "pineapple"],
  "spring"=>["grape"]
}

I did:

def sort_fruits(fruits_hash)
  fruits=[]
  sorted = {}
  seasons = fruits_hash.map {|k, v|v[:season]}
  seasons.uniq.each do |season|
    fruits.clear
    fruits_hash.each do |fruit, season_name|
      if season == season_name[:season]
        fruits << fruit
      end
    end
    p sorted[season] = fruits ## season changes to new season, so this should have created new key/value pair for new season.
  end
  sorted
end

I get:

{
  "winter"=>["grape"],
  "summer"=>["grape"],
  "spring"=>["grape"]
}

I couldn't figure out why adding new key/value pair with unique key would overwrite existing pair in a hash. Any help with explanation would be greatly appreciated.


Solution

  • In Ruby mutable objects are passed by reference. It means that when you iterate over seasons in each block this line:

    sorted[season] = fruits
    

    saves to sorted[season] a reference to fruits, for every season. After each loop finishes every season has a reference to the same fruits array, which contain items calculated on the last step of the iterator. In your case, it's ["grape"].