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

孤人 提交于 2020-01-06 05:44:27

问题


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.


回答1:


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"].




回答2:


Your problem is that you reuse the same fruits array for all the values. Even though you clear it, is is still the same array. If instead of fruits.clear you use fruits = [] then you won't have the issue.

You can see the issue in the following as an example:

arr = ['val']
hash = {
  key1: arr,
  key2: arr
}
p hash # => { key1: ['val'], key2: ['val'] }

arr.clear
p hash # => { key1: [], key2: [] }

You could alternatively use sorted[season] = fruits.clone or sorted[season] = [*fruits] ... anything that uses a new array.

You have to keep track of when you use 'mutation' methods (those that change objects in-place such as clear) - this is a common pitfall when working with hashes and arrays



来源:https://stackoverflow.com/questions/52806431/next-key-value-pair-overwrites-the-existing-pair-in-a-hash-while-trying-to-add-p

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!