What do you expect if you want to compute an inverted Hash?
Wouldn't you expect that:
Let's see what Ruby's built-in Hash.invert method does to a hash:
h = {"eins"=>1, "drei"=>3, "uno"=>1, "one"=>1, "two"=>2, "san"=>3, "ichi"=>1, "three"=>3, "four"=>4}
h.invert
=> {1=>"one", 2=>"two", 3=>"drei", 4=>"four"}
# the above result IS SIMPLY WRONG! Why?
h.invert.invert
=> {"two"=>2, "one"=>1, "drei"=>3, "four"=>4}
h.invert.invert == h
=> false
Not only is the above result very questionable, but you actually lose data which was stored in the original hash.
I would say that Ruby's built-in Hash.invert method is simply broken! For an explanaition on why, see below
> h = {"eins"=>1, "drei"=>3, "uno"=>1, "one"=>1, "two"=>2, "san"=>3, "ichi"=>1, "three"=>3, "four"=>4}
=> {"uno"=>1, "three"=>3, "two"=>2, "eins"=>1, "ichi"=>1, "san"=>3, "one"=>1, "drei"=>3, "four"=>4}
> h.inverse
=> {1=>["one", "ichi", "eins", "uno"], 2=>"two", 3=>["drei", "san", "three"], 4=>"four"}
> h.inverse.inverse
=> {"uno"=>1, "three"=>3, "two"=>2, "eins"=>1, "san"=>3, "ichi"=>1, "one"=>1, "drei"=>3, "four"=>4}
> h.inverse.inverse == h
=> true
Isn't that a much more pleasing result?
class Hash alias old_invert invert def invert self.inverse end end
If you always want to overload the Hash.invert method , you can modify the file invert_hash.rb , by removing the line which contains __END__
Hash.inverse is also available through the Ruby Facets library.
... and is referenced in the Ruby Cookbook
Why is Ruby's Hash.invert broken?
I beleive that it's broken because of an inaccurate design-assumption.
If you studied algorithms in computer science, then you learned that a hash is a data structure which has a mapping function to compute a key for each piece of data you want to place in the hash, e.g. f(value) = key . The key-concept of a hash is that the key is computed from the data/value. And often (for a hashes without collision resolution) the algorithm designers assume that the key is unique for each piece of data, and that no two pieces of data generate the same key:
(A1) Foreach f(value1) = key1 , f(value2) = key2 : value1 != value2 <==> key1 != key2
That means in plain English: each value has only one key, and each key has only one value
Now here's what's wrong with Ruby's implementation of class Hash, and why class Hash in Ruby is not the same as a hash datastructure in CS at all!
Now Ruby's Hash.invert method was probably based on assumption A1 , which is not necessarily true for the data we may want to put into the hash.. that's why Hash.invert is not working properly..