A Hash is a dictionary-like collection of key-value pairs, wherein the keys are unique. (The values need not be unique.)
A Hash has certain similarities to an Array, but:
- An Array index is always an Integer.
- A Hash key can be (almost) any object.
- Hash Data Syntax
- Common Uses
- Creating a Hash
- Hash Value Basics
- Chaining Method Calls
- Method Calls with Blocks
- Methods Returning Enumerators
Until its version 1.9, Ruby supported only the "hash rocket" syntax for Hash data:
h = {:foo => 0, :bar => 1, :baz => 2}
h # => {:foo=>0, :bar=>1, :baz=>2}
(The "hash rocket" is =>, sometimes in other languages called the "fat comma.")
Beginning with version 1.9, you can write a Hash key that's a Symbol in a JSON-style syntax, where each bareword becomes a Symbol:
h = {foo: 0, bar: 1, baz: 2}
h # => {:foo=>0, :bar=>1, :baz=>2}
You can also use Strings instead of barewords:
h = {'foo': 0, 'bar': 1, 'baz': 2}
h # => {:foo=>0, :bar=>1, :baz=>2}
And you can mix the styles:
h = {foo: 0, :bar => 1, 'baz': 2}
h # => {:foo=>0, :bar=>1, :baz=>2}
But it's an error to try the JSON-style syntax for a key that's not a bareword or a String:
h = {0: 'zero'} # Raises SyntaxError (syntax error, unexpected ':', expecting =>)
You can use a Hash to give names to objects:
matz = {name: 'Matz', language: 'Ruby'}
matz # => {:name=>"Matz", :language=>"Ruby"}
You can use a Hash to give names to method arguments:
def some_method(hash)
p hash
end
some_method({foo: 0, bar: 1, baz: 2}) # => {:foo=>0, :bar=>1, :baz=>2}
Note: when the last argument in a method call is a Hash, the curly braces may be omitted:
some_method(foo: 0, bar: 1, baz: 2) # => {:foo=>0, :bar=>1, :baz=>2}
You can use a Hash to initialize an object:
class Dev
attr_accessor :name, :language
def initialize(hash)
hash.each_pair do |key, value|
setter_method = "#{key}=".to_sym
send(setter_method, value)
end
end
end
matz = Dev.new(name: 'Matz', language: 'Ruby')
matz # => #<Dev: @name="Matz", @language="Ruby">
Here are three ways to create a Hash:
- Constructor method: Hash.new.
- Literal method: Hash[].
- Implicit Form: {}.
You can create a Hash by using the constructor method, Hash.new.
Create an empty Hash:
h = Hash.new
h # => {}
h.class # => Hash
You can create a Hash by using its literal method, Hash[].
Create an empty Hash:
h = Hash[]
h # => {}
Create a Hash with initial entries:
h = Hash[foo: 0, bar: 1, baz: 2]
h # => {:foo=>0, :bar=>1, :baz=>2}
You can create a Hash by using its implicit form (curly braces).
Create an empty Hash:
h = {}
h # => {}
Create a Hash with initial entries:
h = {foo: 0, bar: 1, baz: 2}
h # => {:foo=>0, :bar=>1, :baz=>2}
The simplest way to get a Hash value (instance method []):
h[:foo] # => 0
The simplest way to create or update a Hash value (instance method []=):
h[:bat] = 3 # => 3
h # => {:foo=>0, :bar=>1, :baz=>2, :bat=>3}
h[:foo] = 4 # => 4
h # => {:foo=>4, :bar=>1, :baz=>2, :bat=>3}
The simplest way to delete a Hash entry (instance method delete):
h.delete(:bat) # => 3
h # => {:foo=>4, :bar=>1, :baz=>2}
Many Hash instance methods return self. For those methods, you can chain method calls:
h = {foo: 0, bar: 1, baz: 2}
h.keep_if { |key, value| key.start_with?('b') }.size # => 2
For some Hash methods, a call to the method can include a block:
- Hash.new { |hash, key| ... } → new_hash
The block initializes the default proc.
There are several other families of methods that can call blocks:
- General iterators: Some Hash methods iterate over hash entries, doing only what the block specifies.
- Specialized iterators: Some Hash methods iterate over hash entries, performing more specific processing.
- Missing-key handlers: Some Hash methods can handle missing keys in a block.
- Duplicate-key handlers: Some Hash methods can handle duplicate keys in a block.
Each of these general iterators traverses Hash entries, doing only what the block specifies, and returning self:
- hash.each_pair { |key, value| ... } → self
Passes each key-value pair to the block. - hash.each { |key, value| ... } → self
Alias for hash.each. - hash.each_key { |key| ... } → self
Passes each key pair to the block. - hash.each_value { |value| ... } → self
Passes each value pair to the block.
- hash.to_h { |key, value| ... } → new_hash
Passes each key-value pair to the block; returns a new Hash based on the block's return values.
Each of these iterators returns a new Hash, including or excluding entries based on whether the block returns a truthy value:
- hash.filter { |key, value| ... } → new_hash
Passes each key-value pair to the block; includes the entry if and only if the block returns a truthy value. - hash.select { |key, value| ... } → new_hash
Alias for hash.filter. - hash.reject { |key, value| ...} → new_hash
Passes each key-value pair to the block; includes the entry if and only if the block returns a false or nil.
Each of these iterators returns self, retaining or deleting entries based on whether the block returns a truthy value:
- hash.delete_if { |key, value| ... } → self
Passes each key-value pair to the block; deletes each entry for which the block returns a truthy value. - hash.keep_if { |key, value| ... } → self
Passes each key-value pair to the block; deletes each entry for which the block returns false or nil. - ash.filter! { |key, value| ... } → self or nil
Passes each key-value pair to the block; deletes each entry for which the block returns false or nil. (Differs from hash.keep_if by returning nil if no change.) - hash.select! { |key, value| ... } → self or nil
Alias for hash.filter! - hash.reject! { |key, value| ... } → self or nil
Passes each key-value pair to the block; deletes each entry for which the block returns a truthy value. (Differs from hash.delete_if by returning nil if no change.)
Each of these iterators returns a new Hash with modified keys or values based on the block:
- hash.transform_keys { |key| ... } → new_hash
Passes each key to the block, whose return value becomes a key in the new Hash. - hash.transform_values { |value| ... } → new_hash
Passes each value to the block, whose return value becomes a value in the new Hash.
Each of these iterators returns self, modifying keys or values based on the block:
- hash.transform_keys! { |key| ... } → self
Passes each key to the block, whose return value replaces the key. - hash.transform_values! { |value| ... } → self
Passes each value to the block, whose return value replaces the value.
Each of these methods can handle missing keys in a block:
- hash.delete(key) { |key| ... } → value
Calls the block if key is not found; returns the block's return value. - hash.fetch(key) { |key| ... } → value
Calls the block if key is not found; returns the block's return value. - hash.fetch_values(*keys) { |key| ... } → new_array
Calls the block with each missing key; treats the block's return value as the value for that key.
Each of these methods can handle duplicate keys in a block:
- hash.merge(*other_hashes) { |key, old_value, new_value| ... } → new_hash
Returns a new Hash that is the merge of self and *other_hashes. For each duplicate key, calls the block with the key and both values; the block's return value becomes the new value. - hash.merge!(*other_hashes) { |key, old_value, new_value| ... } → self
Returns self with *other_hashes merged. For each duplicate key, calls the block with the key and both values; the block's return value becomes the new value. - hash.update(*other_hashes) { |key, old_value, new_value| ... } → self
Alias for hash.merge!.
Each Hash method that allows a block for iteration returns an Enumerator if no block is given. These are:
- hash.delete_if
- hash.each
- hash.each_key
- hash.each_pair
- hash.each_value
- hash.filter
- hash.filter!
- hash.keep_if
- hash.reject
- hash.reject!
- hash.select
- hash.select!
- hash.transform_keys
- hash.transform_keys!
- hash.transform_values
- hash.transform_values!
Example using method hash.each_pair:
h = {foo: 0, bar: 1, baz: 2}
e = h.each_pair
e # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_pair>`
And perhaps later on:
h1 = e.each { |key, value| puts "#{key}: #{value}"}
h1 # => {:foo=>0, :bar=>1, :baz=>2}
h1.object_id == h.object_id # => true
The enumerator has a reference to the Hash, not a copy of it:
e # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_pair>`
h.delete(:baz) # => 2
e # => #<Enumerator: {:foo=>0, :bar=>1}:each_pair>
But making the original Hash unavailable causes the enumerator to make a copy:
h = nil
e # => #<Enumerator: {:foo=>0, :bar=>1}:each_pair>