I want to keep track of the counts of some arbitarily-named strings and then reset the counts to zero. My thought was to do the following:
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}
...
Now I want to reset new_hash back to reset_hash:
new_hash = reset_hash
=> {"string1"=>1, "string2"=>0, "string3"=>1}
reset_hash
=> {"string1"=>1, "string2"=>0, "string3"=>1}
What is going on here? It seems that reset_hash has actually been set to new_hash, which is the opposite of what I wanted. How do I implement the desired behavior?
We can merge two hashes using the merge() method. When using the merge() method: Each new entry is added to the end. Each duplicate-key entry's value overwrites the previous value.
Equality—Two hashes are equal if they each contain the same number of keys and if each key-value pair is equal to (according to Object#== ) the corresponding elements in the other hash. The orders of each hashes are not compared.
Merge two hashes On of the ways is merging the two hashes. In the new hash we will have all the key-value pairs of both of the original hashes. If the same key appears in both hashes, then the latter will overwrite the former, meaning that the value of the former will disappear. (See the key "Foo" in our example.)
You might get your key and value from user input, so you can use Ruby . to_sym can convert a string to a symbol, and . to_i will convert a string to an integer.
When you have a variable pointing to an object, you really just have a reference to the object. If both a and b point to the hash {1=>3, "foo" => 54}, changing a or b will change the other.
However, you can use a combination of two methods to make what you want.
A default value for the hash:
new_hash = Hash.new(0)
This gives unused values a default value of 0:
new_hash["eggs"] # -> 0
You can then add counts:
new_hash["string1"] += 1 # => 1
When you're done just call
new_hash.clear # => {}
and your hash will be reset, but new accesses will still default to 0.
Note that if you set the default value to a type of object other than a number you may be able to change things due to the whole reference issue noted above.
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"
To get around this you can pass a block to you hash:
h = Hash.new {|hash, key| hash[key] = "new default value"}
This creates a new object at key each time, so changes to one won't ripple:
d = Hash.new{ |hash,key| hash[key] = "string"} #=> {}
d[3] # => "string"
d[3].upcase! #=> "STRING"
d[5] #=> "string"
As others mentioned you have to use clone. Your task should look like this:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With