代码之家  ›  专栏  ›  技术社区  ›  Evan Zamir

将hash设置为Ruby中的另一个hash

  •  4
  • Evan Zamir  · 技术社区  · 12 年前

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

    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,这与我想要的正好相反。我如何实现期望的行为?

    4 回复  |  直到 12 年前
        1
  •  4
  •   Paul Rubel    12 年前

    当你有一个变量指向一个对象时,你实际上只是引用了这个对象。如果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"
    

    为了解决这个问题,您可以将一个块传递给您的hash:

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

    这样每次都会在关键点创建一个新对象,因此对其中一个对象的更改不会产生涟漪:

    d = Hash.new{ |hash,key| hash[key] = "string"} #=> {}
    d[3] # => "string"
    d[3].upcase! #=> "STRING"
    d[5] #=> "string"
    
        2
  •  4
  •   Иван Бишевац    12 年前

    正如其他人提到的,你必须使用 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
    
        3
  •  1
  •   Dave Newton    12 年前

    您正在修改一个散列。

    两个变量都引用相同的散列。当您更改散列中的一个项时,两个引用都会反映出该更改——因为它是相同的散列指令。

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

        4
  •  1
  •   Community CDub    7 年前

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

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

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

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