Flowdock

A Hash is a collection of key-value pairs. It is similar to an Array, except that indexing is done via arbitrary keys of any object type, not an integer index. The order in which you traverse a hash by either key or value may seem arbitrary, and will generally not be in the insertion order.

Hashes have a default value that is returned when accessing keys that do not exist in the hash. By default, that value is nil.

Hash uses key.eql? to test keys for equality. If you need to use instances of your own classes as keys in a Hash, it is recommended that you define both the eql? and hash methods. The hash method must have the property that a.eql?(b) implies a.hash == b.hash.

  class MyClass
    attr_reader :str
    def initialize(str)
      @str = str
    end
    def eql?(o)
      o.is_a?(MyClass) && str == o.str
    end
    def hash
      @str.hash
    end
  end

  a = MyClass.new("some string")
  b = MyClass.new("some string")
  a.eql? b  #=> true

  h = {}

  h[a] = 1
  h[a]      #=> 1
  h[b]      #=> 1

  h[b] = 2
  h[a]      #=> 2
  h[b]      #=> 2
Show files where this class is defined (3 files)
Register or log in to add new notes.
August 14, 2008 - (v1_8_6_287)
11 thanks

Convert an Array to a Hash

The Hash.[] method converts an even number of parameters to a Hash. (The Hash[] method depends on the Hash class, but don’t confuse the method with the class itself). For example:

Hash['A', 'a', 'B', 'b']
# => {"A"=>"a", "B"=>"b"}

You can convert an array to a hash using the Hash[] method:

array = ['A', 'a', 'B', 'b', 'C', 'c']
hash = Hash[*array]
# => {"A"=>"a", "B"=>"b", "C"=>"c"}  

The * (splat) operator converts the array into an argument list, as expected by Hash[].

You can similarly convert an array of arrays to a Hash, by adding flatten:

array = [['A', 'a'], ['B', 'b'], ['C', 'c']]
hash = Hash[*array.flatten]  
# => {"A"=>"a", "B"=>"b", "C"=>"c"}

This also comes in handy when you have a list of words that you want to convert to a Hash:

Hash[*%w(
  A a
  B b
  C c
)]
# => {"A"=>"a", "B"=>"b", "C"=>"c"}
May 2, 2009
8 thanks

Create a Hash from two Arrays

Here is my favorite idiom for creating a Hash from an Array of keys and an Array of values:

keys = [:a, :b]
values = [1,2]
h = Hash[*keys.zip(values).flatten]      # => {:b=>2, :a=>1}
May 17, 2010
2 thanks

Add has_keys? method to Hash class

class Hash

def has_keys?(*_keys)
  (_keys - self.keys).empty?
end

end

h = {1=>‘a’,2=>‘b’}

h.has_keys?(1,2) #-> true

h.has_keys?(1,3) #-> false

March 17, 2010
0 thanks

Create new Hash as subset of another a different way

or

only keys

old_hash = { :a => 'A', :b => 'B', :c => 'C', :d => 'D', :e => 'E', :f => 'F' }
only_keys = [ :a, :c, :f ]
new_hash = old_hash.delete_if { |k, v| !only_keys.include? k }

only values

old_hash = { :a => 'A', :b => 'B', :c => 'C', :d => 'D', :e => 'E', :f => 'F' }
only_values = [ 'A', 'D', 'G' ]
new_hash = old_hash.delete_if { |k, v| !only_values.include? v }

there are many ways to skin a cat :)

August 15, 2008
0 thanks

Convert a Hash to an Array of Arrays using map

Although you‘ll always have to_a and it‘s faster, this trick is too cool to ignore…

Convert a Hash to an Array of Arrays using Enumerable#map

June 13, 2010
0 thanks

keys to/from symbols

There’s probably a more effecient way to do this…

class Hash

def keys_to_strings
  res = {}
  self.keys.each do |k|
    if self[k].is_a?(Hash)
      res[k.to_s] = self[k].keys_to_strings
    else
      res[k.to_s] = self[k]
    end
  end
  return res
end

def keys_to_symbols
  res = {}
  self.keys.each do |k|
    if self[k].is_a?(Hash)
      res[k.to_sym] = self[k].keys_to_symbols
    else
      res[k.to_sym] = self[k]
    end
  end
  return res
end

end
June 13, 2010
0 thanks

Add requires!

Useful for methods that take options = {}

class Hash

def requires!(*params)
  params.each do |param| 
    raise ArgumentError.new("Missing required parameter: #{param}") unless self.has_key?(param) 
  end
end

end
June 13, 2011
0 thanks

Generalized Zip

My 5 cents.

I find trully useful this. Is a kind of generalized zip. You can combine 2 or more enumerables (arrays or others) of any size into a hash, array of arrays, .… The size of the result is the size of the bigest of the enumerables. For the shortests enumerables nil elements are used at the end.

# method compose
def compose(*enumerables)
  res=[]
  enumerables.map(&:size).max.times do
    tupla=[]
    for enumerable in enumerables
      tupla << enumerable.shift
    end
    res << (block_given? ? yield(tupla) : tupla)
  end
  res
end

some examples:

en1= [1, 2, 3, 4]
en2= ['a', 'b', 'c', 'd', 'e']
en3= {:elem1 => "1", :elem2 => "2", :elem3 => "3"}

p compose en1.dup, en2.dup, en3.dup
p a1=compose(en2.dup, en1.dup) {|a,b| {a.to_sym => b}}

p a1.inject({}) {|ac,item| ac.merge item}
p a1.flatten

p a2=compose(en2.dup, en1.dup).flatten
p Hash[*a2]

p a3=compose(en2.dup, en3.dup).flatten

Their outputs are:

#[[1, "a", [:elem1, "1"]], [2, "b", [:elem2, "2"]], [3, "c", [:elem3, "3"]], [4, "d", nil], [nil, "e", nil]]
#[{:a=>1}, {:b=>2}, {:c=>3}, {:d=>4}, {:e=>nil}]
#{:b=>2, :d=>4, :e=>nil, :c=>3, :a=>1}
#[{:a=>1}, {:b=>2}, {:c=>3}, {:d=>4}, {:e=>nil}]
#["a", 1, "b", 2, "c", 3, "d", 4, "e", nil]
#{"a"=>1, "b"=>2, "c"=>3, "d"=>4, "e"=>nil}
#["a", :elem1, "1", "b", :elem2, "2", "c", :elem3, "3", "d", nil, "e", nil]
March 17, 2010 - (>= v1_8_7_72)
0 thanks

Create new Hash as subset of another

old_hash = {:a=>‘A’,:b=>‘B’,:c=>‘C’,:d=>‘D’,:e=>‘E’,:f=>‘F’}

only_keys = [:a,:c,:f]

new_hash = Hash[*old_hash.find_all{|k,v| only_keys.member?(k)}.flatten]

# => {:a=>“A”, :c=>“C”, :f=>“F”}

or for values

only_vals = [‘A’,‘D’,‘G’]

new_hash = Hash[*old_hash.find_all{|k,v| only_vals.member?(v)}.flatten]

# => {:a=>“A”, :d=>“D”}