Hashes in Ruby
A basic data structure in Ruby, hashes are collections of distinct key-value pairs. Since they associate keys with values, they are sometimes referred to as maps, dictionaries, or associative arrays. Hashes allow any object to be used as a key, in contrast to arrays, which utilize integer indices.
Key Characteristics of Hashes
Key-Value Association: Each unique key in a hash is linked to a particular value, and hashes store data as pairs.
Unique Keys: A hash requires that every key be distinct.
Object References: A hash contains object references rather than copies. All references to an object that is referenced within a hash will therefore change if that object is modified.
Ordering: Historically, hashes lacked a natural order guarantee. Nevertheless, elements are iterated in their insertion order with Ruby 1.9 and later. The iteration’s order remains unchanged if a key’s value is modified or reinserted.
Efficiency: In general, it is very efficient to look up values by key in a hash; this is frequently similar to array lookups. Keys must have unique hash codes in order for this efficiency to exist.
Mutability of Keys: There may be issues when using a mutable object as a key, such as an array or another hash. The hash code of a mutable key may change after it has been included to a hash if its content changes, rendering it unretrievable. An internal copy is created by Ruby for strings that are used as hash keys. It is possible to use Hash#rehash to fix mutable key problems after mutation.
Creating Hashes
There are various techniques to generate hashes:
- Literal Syntax: Using curly braces
{}
with key-value pairs separated by=>
(or:
for symbol keys in Ruby 1.9+). - In a method call, curly brackets can be skipped when a hash literal is the last argument.
Hash.new
Method: Makes the hash empty.Hash[]
Operator: From an array of key-value arrays or a list of keys and values that alternate.- With Default Values: When accessing a nonexistent key, you can specify a block to compute a dynamic default or a default value to be returned.
Accessing Values in Hashes
- Element Reference
[]
: Retrieves the value that a key is connected with. It returns either the provided default value or nil by default if the key cannot be located. - Unless specifically converted, string keys not symbols must be accessed via string keys.
fetch
Method: Gives you additional control in the event that a key is lost. A KeyError exception may be raised, a block may be executed, or a given default value may be returned.keys
andvalues
Methods: Give back arrays containing all of the hash’s keys or values.
Code example
person = { "name" => "Alice", "age" => 30 }
movie = { title: "Inception", director: "Christopher Nolan" }
puts person["name"]
puts movie[:title]
Output
Alice
Inception
Modifying Hashes
Element Assignment []=
: Overrides any previous value for a key by associating it with a value.
store
Method: A synonym for []=
.
clear
Method: Removes all key-value pairs from the hash.
delete
Method: Returns the value of the supplied key after deleting the record for it. Able to take a block to deal with missing keys.
delete_if
Method: Removes each key-value pair that a block evaluates to true.
merge
and merge!
Methods: Combine hashes. While merge! yields a new hash. The original hash is altered. Duplicate key conflicts can be settled with a block.
Modifying Keys and Values with inject
or each_with_object
: A new hash can be produced by transforming keys or values using these techniques.
Code example
person = { "name" => "Govindhtech", "age" => 3 }
# Add a new key-value pair
person["occupation"] = "Digital Marketing"
puts person
# Update an existing key's value
person["age"] = 2
puts person
Output
{"name" => "Govindhtech", "age" => 3, "occupation" => "Digital Marketing"}
{"name" => "Govindhtech", "age" => 2, "occupation" => "Digital Marketing"}
Iterating Over Hashes
The Enumerable module is a part of hashes and offers a variety of iteration techniques.
each
or each_pair
: Repeatedly pass each key-value pair to a block.
each_key
: Iterates over keys only.
each_value
: Iterates over values only.
each_with_index
: Iterates over elements and provides the index of the iteration.
Sorted Iteration: Converting the hash to an array (such as a key-value pair array) and sorting the array are standard ways to iterate in a certain order.
If you frequently need to maintain insertion order, the orderedhash
library offers an OrderedHash
class.
Code example
person = { name: "Govindhtech", age: 3, city: "Chittoor" }
# Iterate through each key-value pair
person.each do |key, value|
puts "#{key}: #{value}"
end
Output
name: Govindhtech
age: 3
city: Chittoor
Conversions
To/From Arrays: Using to_a, hashes can be transformed into arrays of [key, value] pairs. With to_h, they can be generated from such arrays. A single-dimensional array of alternating keys and values can be created from a hash using the flatten technique.
To YAML: With the help of the yaml package and the to_yaml method, hashes can be serialized into the human-readable data format known as YAML (Yet Another Markup Language).
Advanced Considerations
Custom Objects as Keys and Hash Codes: You must override both the hash and eql? methods if you construct a custom class and want to use its instances as hash keys. Two objects must return the same integer value from their hash methods if they are eql? (considered equal). The hash codes of the instance variables that define equality are often combined in a suitable hash algorithm.
Modules and Hashes: It is possible to think about Ruby modules as hashes.
Distributed Hashes: Hash-like data structures can be shared between several machines using libraries like MemCached or DRb (Distributed Ruby) for applications that need shared, persistent storage over a network.
You can also read Arrays In Ruby: An Ordered Collections With Integer Indexes