【问题标题】:Setting hash equal to another hash in Ruby在 Ruby 中设置哈希等于另一个哈希
【发布时间】:2012-07-15 17:53:17
【问题描述】:

我想跟踪一些任意命名的字符串的计数,然后将计数重置为零。我的想法是做以下事情:

reset_hash={"string1"=>0,"string2"=>0,"string3"=>0}
=> {"string1"=>0, "string2"=>0, "string3"=>0} 

new_hash = reset_hash
=> {"string1"=>0, "string2"=>0, "string3"=>0} 

new_hash["string1"]=1
new_hash["string3"]=1
new_hash
=> {"string1"=>1, "string2"=>0, "string3"=>1}

...

现在我想将 new_hash 重置为 reset_hash:

new_hash = reset_hash
=> {"string1"=>1, "string2"=>0, "string3"=>1}
reset_hash
=> {"string1"=>1, "string2"=>0, "string3"=>1} 

这里发生了什么?看来reset_hash实际上已经设置为new_hash,这与我想要的相反。如何实现所需的行为?

【问题讨论】:

    标签: ruby hashtable


    【解决方案1】:

    您正在修改单个哈希。

    两个变量都引用同一个哈希。当您更改哈希中的项目时,两个引用都会反映该更改 - 因为它是相同的哈希实例。

    也许您想先复制哈希?如果你这样做了,并且你有一个包含复杂对象的哈希,你还需要研究浅拷贝和深拷贝/克隆。

    【讨论】:

    • 我以为我在复制哈希。那么我该如何正确地做到这一点呢?
    • 您正在将 reference 复制到散列;您需要使用clone (docs),注意注意事项。有很多方法可以进行深度克隆,包括仅对对象进行编组/解组。
    【解决方案2】:

    您需要使用克隆来制作副本。

    https://stackoverflow.com/a/4157438/1118101

    否则,您只会创建 2 个指向同一个哈希的“指针”,而不是复制内容。

    然后使用替换将克隆的内容复制回您现有的哈希中。

    【讨论】:

      【解决方案3】:

      当你有一个指向一个对象的变量时,你实际上只是有一个对该对象的引用。如果 a 和 b 都指向哈希 {1=>3, "foo" => 54},则更改 a 或 b 将更改另一个。

      但是,您可以结合使用两种方法来制作您想要的东西。

      哈希的默认值:

      new_hash = Hash.new(0)
      

      这为未使用的值提供了默认值 0:

      new_hash["eggs"]  # -> 0
      

      然后您可以添加计数:

      new_hash["string1"] += 1 # => 1
      

      完成后打电话

      new_hash.clear # => {}
      

      并且您的哈希值将被重置,但新访问仍将默认为 0。

      请注意,如果您将默认值设置为数字以外的对象类型,您可能会因为上面提到的整个参考问题而改变事物。

      irb(main):031:0> b = Hash.new("Foo") #=> {}
      irb(main):032:0> b[3] #=> "Foo"
      irb(main):033:0> b[33] #=> "Foo"
      irb(main):034:0> b[33].upcase! #=> "FOO"
      irb(main):035:0> b[3] # => "FOO"
      

      要解决这个问题,您可以将一个块传递给您的哈希:

      h = Hash.new {|hash, key| hash[key] = "new default value"}
      

      这每次都会在 key 处创建一个新对象,因此对一个对象的更改不会产生涟漪:

      d = Hash.new{ |hash,key| hash[key] = "string"} #=> {}
      d[3] # => "string"
      d[3].upcase! #=> "STRING"
      d[5] #=> "string"
      

      【讨论】:

        【解决方案4】:

        正如其他人提到的,您必须使用clone。您的任务应如下所示:

        reset_hash={"string1"=>0,"string2"=>0,"string3"=>0}
        new_hash = reset_hash.clone
        
        new_hash["string1"]=1
        new_hash["string3"]=1
        new_hash
        
        new_hash = reset_hash.clone
        reset_hash
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-02-05
          • 1970-01-01
          • 2013-07-21
          • 1970-01-01
          • 2011-04-19
          • 2014-03-30
          • 1970-01-01
          相关资源
          最近更新 更多