Class: Hash

Inherits:
Object
  • Object
show all
Defined in:
lib/helpers/invert_hash.rb,
lib/helpers/hash_extensions.rb

Overview

Project Homepage: www.unixgods.org/~tilo/Ruby/invert_hash.html

This also appears in the “Facets of Ruby” library, and is mentioned in the O'Reilly Ruby Cookbook

Ruby's Hash.invert method can't handle the common case that two or more hash entries have the same value.

hash.invert.invert == h    # => ?       # is not generally true for Ruby's standard Hash#invert method

hash.inverse.inverse == h  # => true    # is true, even if the hash has duplicate values

If you have a Math background, you would expect that performing an “invert” operation twice would result in the original hash.

The Hash#inverse method provides this.

If you want to permanently overload Ruby's original invert method, you may want to do this:

class Hash
  alias old_invert invert   # old Hash#invert is still accessible as Hash#old_invert

  def invert
    self.inverse            # Hash#invert is not using inverse method
  end
end

Instance Method Summary collapse

Instance Method Details

#inverseObject

Returns a new hash, using given hash's values as keys and using keys as values. If the input hash has duplicate values, the resulting hash will contain arrays as values. If you perform inverse twice, the output is identical to the original hash. e.g. no data is lost.

hash = { 'zero' => 0 , 'one' => 1, 'two' => 2, 'three' => 3 ,   # English numbers
         'null' => 0, 'eins' => 1, 'zwei' => 2 , 'drei' => 3 }  # German numbers

# Hash#inverse keeps track of duplicates, and preserves the input data

hash.inverse          # => { 0=>["null", "zero"], 1=>["eins", "one"], 2=>["zwei", "two"], 3=>["drei", "three"] }

hash.inverse.inverse  # => { "null"=>0, "zero"=>0, "eins"=>1, "one"=>1, "zwei"=>2, "two"=>2, "drei"=>3, "three"=>3 }

hash.inverse.inverse == hash  # => true   # works as you'd expect

# In Comparison:
# 
# the standard Hash#invert loses data when dupclicate values are present

hash.invert           # => { 0=>"null", 1=>"eins", 2=>"zwei", 3=>"drei" }
hash.invert.invert    # => { "null"=>0, "eins"=>1, "zwei"=>2, "drei"=>3 }   # data is lost

hash.invert.invert == hash   # => false   # oops, data was lost!

83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/helpers/invert_hash.rb', line 83

def inverse
  i = Hash.new
  self.each_pair{ |k,v|
    if (v.class == Array)
      v.each{ |x|
        if i.has_key?(x)
          i[x] = [k,i[x]].flatten
        else
          i[x] = k
        end
      }
    else
      if i.has_key?(v)
   i[v] = [k,i[v]].flatten
      else
        i[v] = k
      end
    end
  }
  return i
end

#invertObject

monkey-patching Hash#invert method - it's backwards compatible, but preserves duplicate values in the hash


15
16
17
# File 'lib/helpers/hash_extensions.rb', line 15

def invert
  self.inverse
end

#old_invertObject

original Hash#invert is still available as Hash#old_invert


12
# File 'lib/helpers/hash_extensions.rb', line 12

alias old_invert invert