【问题标题】:Recursive function in ruby is overwriting nested attributes of cloned(object.dup) variableruby 中的递归函数正在覆盖 cloned(object.dup) 变量的嵌套属性
【发布时间】:2024-01-08 17:25:02
【问题描述】:

我有一个这样的哈希:

entity = {1=> nil, 2 => {3 => nil, 4 => 1}}

我写了一个函数,它可以使用递归删除给定实体的空值。

def clear_null_values(entity)
   entity.each do |key, value|
     if value == nil || value.blank?
       entity.delete(key)
     elsif value.is_a? Hash
       clear_null_values(value)
       entity.delete(key) if value.blank?
     end
   end
end 

而且我还需要原始实体用于其他目的。所以我复制了哈希变量,然后清除了空值。

final_entity = entity.dup
clear_null_values(entity)
puts entity
puts final_entity

结果:

{2 => {4 => 1}}
{1=> nil, 2 => {4 => 1}} # the nested values are overwritten.

理想情况下,final_entity 应该与原始实体相同。

问题1:为什么entity.dup只复制outerhash?

问题2:如何使 final_entity 完全复制原始实体,即即使我们修改实体,那么 final_entity 也不应该改变?

【问题讨论】:

  • 我知道您想计算{2 => {4 => 1}},但不明白{1=> nil, 2 => {4 => 1}} 是如何确定的,因为它只包含nil 中的一个nilentity。我相信您的问题需要 Rails 标记,因为 blank 不是 Ruby 方法。
  • 你的问题是什么?
  • 用标签和更多解释更新了问题。
  • @CarySwoveland 没有构造{1=> nil, 2 => {4 => 1}} 的标准,因为措辞不当的问题是如何避免这个结果并拥有final_entity == 原始实体,entity.dup 产生的问题仅适用于最外层的哈希.
  • @Michael,我明白了。 “result”后面的第二行是OP的错误结果,不是想要的结果。

标签: ruby-on-rails ruby hash clone dup


【解决方案1】:

尝试改用deep_dup,您的原始代码仅dup-ed 最外层的哈希。

final_entity = entity.deep_dup
clear_null_values(entity)
puts entity
puts final_entity

输出:

{2=>{4=>1}}
{1=>nil, 2=>{3=>nil, 4=>1}}

注意:Rails 还添加了Hash#compact,您可以使用它来简化clear_null_values

【讨论】:

  • deep_dup 就像一个魅力。感谢其他建议,但我使用的是 Rails 3.2,所以 Hash#compact 不起作用。
【解决方案2】:

在我看来,通过直接对 entities 操作而不是在其副本上操作来计算去除了 nil 值的哈希值会更简洁。

def clear_null_values(entity)
  entity.each_with_object({}) do |(k,v),h|
    next if v.nil?
    h[k] = Hash === v ? clear_null_values(v) : v
  end
end

entities = { 1=>nil, 2=>{ 3=>nil, 4=>1 } }

clear_null_values entities
  #=> {2=>{4=>1}}

我们可以确认entities 没有发生变异。

entities
  #=> {1=>nil, 2=>{3=>nil, 4=>1}}

【讨论】:

最近更新 更多