是什么导致了这里的问题?
当我在 ruby 中运行此代码时:
updated_users = []
users = [{:name => "sam" , :number => 001 }]
ids = ["aa" , "bb" , "cc"]
users.each do |user|
ids.each do |id|
user[:guid] = id
updated_users << user
end
end
p updated_users
我得到:
[{:name=>"sam", :number=>1, :guid=>"cc"},
{:name=>"sam", :number=>1, :guid=>"cc"},
{:name=>"sam", :number=>1, :guid=>"cc"}]
我希望得到:
[{:name=>"sam", :number=>1, :guid=>"aa"},
{:name=>"sam", :number=>1, :guid=>"bb"},
{:name=>"sam", :number=>1, :guid=>"cc"}]
发生了什么,我应该如何获得所需的输出?
回答
您的问题反映了初露头角的 Ruby 开发者普遍存在的误解。您从以下内容开始:
updated_users = []
users = [{:name => "sam" , :number => 001 }]
ids = ["aa" , "bb" , "cc"]
users是一个包含单个散列的数组。让我们注意该哈希对象的 id:
users.first.object_id
#=> 1440
现在让我们通过puts添加一些语句来执行您的代码,看看发生了什么。
users.each do |user|
puts "user = #{user}"
puts "user.object_id = #{user.object_id}"
ids.each do |id|
puts "nid = #{id}"
user[:guid] = id
puts "user = #{user}"
puts "user.object_id = #{user.object_id}"
updated_users << user
puts "updated_users = #{updated_users}"
updated_users.size.times do |i|
puts "updated_users[#{i}].object_id = #{updated_users[i].object_id}"
end
end
end
这将显示以下内容。
user = {:name=>"sam", :number=>1}
user.object_id = 1440
到现在为止还挺好。现在开始ids.each循环:
id = aa
user = {:name=>"sam", :number=>1, :guid=>"aa"}
user.object_id = 1440
由于user之前没有 key :guid,因此将键值对:guid=>"aa"添加到user。请注意,user的 id 没有改变。user然后附加到(空)数组updated_users:
updated_users = [{:name=>"sam", :number=>1, :guid=>"aa"}]
updated_users[0].object_id = 1440
这也是我们应该期待的。ids然后处理的下一个元素:
id = bb
user = {:name=>"sam", :number=>1, :guid=>"bb"}
user.object_id = 1440
由于user有一个键,:guid这只会将该键的值从 更改"aa"为"bb"。user然后附加到updated_users:
updated_users = [{:name=>"sam", :number=>1, :guid=>"bb"},
{:name=>"sam", :number=>1, :guid=>"bb"}]
updated_users[0].object_id = 1440
updated_users[1].object_id = 1440
该数组的第一个和第二个元素被视为同一个对象user,因此更改:user的键值会:guid以相同的方式影响两个元素。
ids处理第三个也是最后一个元素时会发生同样的事情:
id = cc
user = {:name=>"sam", :number=>1, :guid=>"cc"}
user.object_id = 1440
updated_users = [{:name=>"sam", :number=>1, :guid=>"cc"},
{:name=>"sam", :number=>1, :guid=>"cc"},
{:name=>"sam", :number=>1, :guid=>"cc"}]
updated_users[0].object_id = 1440
updated_users[1].object_id = 1440
updated_users[2].object_id = 1440
知道了?
要获得您想要的结果,您需要附加updated_users来自user以下内容的不同哈希值:
users.each do |user|
ids.each do |id|
updated_users << user.merge(guid: id)
end
end
updated_users
#=> [{:name=>"sam", :number=>1, :guid=>"aa"},
# {:name=>"sam", :number=>1, :guid=>"bb"},
# {:name=>"sam", :number=>1, :guid=>"cc"}]
请注意,users尚未变异(更改):
users
#=> [{:name=>"sam", :number=>1}]
见Hash#merge。请注意,这user.merge(guid: id)是user.merge({ guid: id })或 等价的简写user.merge({ :guid => id })。