0

I'm trying to adjust the values of the hash info for the key "#{item} W/COUPON", without changing the values of info for the key item, which is what seems to be inadvertently happening. All of this is taking place within a nested hash.

hash_with_coupons[item] = info
hash_with_coupons[item][:count] = info[:count] - coupon_hash[:num] 
hash_with_coupons["#{item} W/COUPON"] = info
hash_with_coupons["#{item} W/COUPON"][:price] = coupon_hash[:cost]
hash_with_coupons["#{item} W/COUPON"][:count] = 1

After this code runs,

  • hash_with_coupons[item][:price] == coupon_hash[:cost]
  • hash_with_coupons[item][:count] == 1

But they were supposed to be the original price and info[:count] - coupon_hash[:num], respectively.

Kristján
  • 18,165
  • 5
  • 50
  • 62
  • Can you post more code, maybe showing the data structures you are building using the nested hash? – Beartech Nov 13 '15 at 04:59
  • The best thing is to post enough code so that people can paste it into IRB and test it. – Beartech Nov 13 '15 at 05:01
  • 1
    And if you are using overly complicated hash structures you might want to take a more object oriented approach and use classes, methods, etc. – Beartech Nov 13 '15 at 05:23
  • 2
    I don't think readers will understand your question. (I don't.) I suggest you edit to show `coupon_hash` (`coupon_hash = { ... }`) and also show the hash you want to produce. That may take a few minutes, so I further suggest you delete the question, do the edit, then undelete. The longer you leave it up as is the more likely you'll get downvotes and/or votes to close. – Cary Swoveland Nov 13 '15 at 06:47
  • After the first assignment, `hash_with_coupons[item]` and `info` refer to the same object. Therefore, `hash_with_coupons[item][:count] = ...` is equivalent to `info[:count] = ...`. You might want to assign a (deep) copy of `info` instead. – Stefan Nov 13 '15 at 10:40

1 Answers1

0

The reason your #{item} W/COUPON entry is modifying your item entry is you've handed both of them the same info object. That is, after the two key assignments, your hash looks like this:

{
  item               => info,
  "#{item} W/COUPON" => info
}

Looking at it this way, it's clear that modifying one value modifies the other, and in fact modifies the original info variable - they're all the same object. A simple way to make your hash_with_coupons values independent is to call dup on info as you do the assignment:

hash_with_coupons[item] = info.dup
hash_with_coupons["#{item} W/COUPON"] = info.dup
# Make modifications

Then each of your hash keys gets a copy of info. dup does what's called a shallow copy, making a new Hash object with the same values as the old one. This will work as long as your info hash values are simple, like Fixnums, and not references to more hashes, arrays, etc. that you want to modify. Otherwise, you'll need a deep copy or you'll run into the same problem you're having now, just one level deeper.

Since you're new, I'd recommend taking a different approach to better see which values are ending up in hash_with_coupons. Instead of assigning info and then modifying things inside your hash, assign brand new hashes with the data you want:

hash_with_coupons[item] = {
  price: info[:price],
  count: info[:count] - coupon_hash[:num]
}
hash_with_coupons["#{item} W/COUPON"] = {
  price: info[:price] - coupon_hash[:cost],
  count: 1
}

This guarantees that the values of hash_with_coupons are distinct objects, so you won't accidentally modify both when you change one. It also makes it very clear which values end up where, so you can easily see if you start sharing references again.

Community
  • 1
  • 1
Kristján
  • 18,165
  • 5
  • 50
  • 62