class

Hash

v1_8_7_330 - Show latest stable - Superclass: Object

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

Included modules

  • Enumerable

Files

  • hash.c
  • lib/pp.rb
  • lib/yaml/rubytypes.rb

8Notes

Create a Hash from two Arrays

mindloaf · May 1, 20098 thanks

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}

Add has_keys? method to Hash class

guyboertje · May 17, 20102 thanks
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

Convert a Hash to an Array of Arrays using map

Alex · Aug 15, 2008

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

Create new Hash as subset of another

guyboertje · Mar 17, 2010

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"}

Create new Hash as subset of another a different way

sfusion · Mar 17, 2010

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 :)

keys to/from symbols

wiseleyb · Jun 13, 2010

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

Add requires!

wiseleyb · Jun 13, 2010

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

Generalized Zip

syborg · Jun 13, 2011

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]