Bruno Andrade
Bruno Andrade

Reputation: 13

Updating multiple hash keys after merging values

I have a hash where multiple keys (lets say 1-5) point to one object (lets call a). Keys (6-10) points to another object(say, b).

At some point I merged "b" into "a", now i have to make sure everyone sees the same object (also merging "a" into "b" and creating two objects with same content is not an option)

Is there a way to make any reference to "b" just redirect to "a" (keys 1-10 now point to object a) without manually updating keys 6-10 ?

Upvotes: 0

Views: 318

Answers (2)

Amadan
Amadan

Reputation: 198436

You can't switch out one object for another unless you have some kind of a wrapper. Unless performance matters a lot, the easiest wrappers to use are proxy objects, because you don't need to unwrap them: they transparently behave exactly like the wrapped object.

class ProxyObject
  # thanks to https://alisdair.mcdiarmid.org/invisible-proxies-with-ruby/
  instance_methods.each do |m|
    undef_method(m) unless m =~ /(^__|^nil\?$|^send$|^object_id$)/
  end

  attr_accessor :target

  def initialize(target)
    @target = target
  end

  def respond_to?(symbol, include_priv=false)
    @target.respond_to?(symbol, include_priv)
  end

  private def method_missing(method, *args, &block)
    @target.send(method, *args, &block)
  end
end

a = 1
b = 10
a_proxy = ProxyObject.new(a)
b_proxy = ProxyObject.new(b)
a_proxy.class                   # verify how well they masquerade
# => Integer
hash = 10.times.map { |i| [i + 1, i < 5 ? a_proxy : b_proxy] }.to_h
# => {1=>1, 2=>1, 3=>1, 4=>1, 5=>1, 6=>10, 7=>10, 8=>10, 9=>10, 10=>10} 
hash.values.sum()               # confirm it behaves exactly like a number
# => 55
b_proxy.target = a_proxy.target # switch reference
hash
# => {1=>1, 2=>1, 3=>1, 4=>1, 5=>1, 6=>1, 7=>1, 8=>1, 9=>1, 10=>1}
hash.values.sum()               # confirm the reference is changed
# => 10

Upvotes: 2

Bruno Andrade
Bruno Andrade

Reputation: 13

I think I found an answer but I still have to code it

instead of the hash having an object, it will contain an array

array[0] will originally point to itself, array[1] will be the actual object

so this is the setup: hash1-5 points to arr1, hash6-10 points to arr2, arr1[0] points to itself and arr1[0]

after merging arr2[1] (b in the original question) into arr1[1] (a into the original question), I will update arr2[0] to point to arr1.

finally, after every key retrieval I will run something along the lines of

test = hash[6] while test[0] != test test = test[0] end

Upvotes: 0

Related Questions