Hash
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.
Included modules
- Enumerable
Files
- hash.c
- lib/pp.rb
- lib/yaml/rubytypes.rb
8Notes
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}
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
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
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"}
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 :)
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
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
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]