【问题标题】:What is causing the issue here?是什么导致了这里的问题?
【发布时间】:2021-10-06 11:19:30
【问题描述】:

当我在 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"}]

发生了什么,我应该如何获得所需的输出?

【问题讨论】:

标签: arrays ruby hash


【解决方案1】:

您的问题反映了新兴 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 之前没有键 :guid,因此将键值对 :guid=&gt;"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 =&gt; id })

【讨论】:

  • 感谢您花时间详细解释这一点。我进行了类似的跟踪,并观察到哈希值本身以及包含相同哈希的数组都发生了哈希值更改,但不知道合并方法以避免改变哈希。 object_id 也有助于说明正在发生的事情。谢谢!
猜你喜欢
  • 2021-11-26
  • 2021-09-19
  • 1970-01-01
  • 1970-01-01
  • 2019-07-01
  • 2011-02-12
  • 2011-11-27
  • 2015-09-08
  • 2012-01-22
相关资源
最近更新 更多