下一个键/值对在尝试使用新键添加对时会覆盖哈希中的现有对



我有:

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

我想得到:

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

我做了:

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

我得到:

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

我不明白为什么使用唯一键添加新的键/值对会覆盖哈希中的现有对。任何解释方面的帮助将不胜感激。

在 Ruby 中,可变对象是通过引用传递的。这意味着当您在each中迭代seasons时,会阻止此行:

sorted[season] = fruits

保存以sorted[season]对每个季节的fruits的引用。循环结束后each每个季节都会引用同一个fruits数组,该数组包含在迭代器的最后一步计算的项目。在您的情况下,它是["grape"].

您的问题是对所有值重用相同的fruits数组。即使您清除它,仍然是相同的数组。如果您不使用fruits.clearfruits = []那么您就不会遇到问题。

您可以在以下示例中看到该问题:

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

您也可以使用sorted[season] = fruits.clonesorted[season] = [*fruits]...任何使用新数组的东西。

您必须跟踪何时使用"突变"方法(那些就地更改对象的方法,例如clear( - 这是使用哈希和数组时的常见陷阱

最新更新