This content originally appeared on DEV Community and was authored by Amirul Asyraf
What the heck is Ruby Hash ??
You can think of Ruby Hash is kind of an Array without the numerical indexes. You access the Hash values with Keys
. A Hash is a data structure used to store data in the form of UNIQUE key-value pairs.
A Hash has certain similarities to an Array, but:
✅ An Array index is always an Integer
✅ A Hash key can be (almost) any object
We are gonna dive ? into the Hash world in Ruby. But not too deep, just at the level where most people dive in :p.
note: I encourage you to open
irb
in your favourite terminal app. Make sure you get your hands ? dirty.
TL;DR
- 1️⃣ Hash Data Syntax
- 2️⃣ Common use case of using Hash
- 3️⃣ How to Create a Hash
- 4️⃣ How to create or update a Hash value
- 5️⃣ Values in a Ruby Hash
- 6️⃣ Hash Entry Order
- 7️⃣ How to delete a Hash entry
- 8️⃣ How to Access Values From a Hash
- 9️⃣ Extract a nested Hash value
- ? Hash Keys 101
- 1️⃣1️⃣ Default Values
- 1️⃣2️⃣ How to Merge Two Ruby Hashes
- 1️⃣3️⃣ Multiple Hash values for one key
- 1️⃣4️⃣ Get All Keys and Values From a Hash
- 1️⃣5️⃣ Check if key exists in hash
- 1️⃣6️⃣ How to change a Hash to Array
✅ Hash Data Syntax
Hash has three Syntax style as Ruby 3.0.
1) hash rocket =>
hashy = {:foo => 0, :bar => 1, :baz => 2}
hashy # => {:foo=>0, :bar=>1, :baz=>2}
2) JSON-style syntax
hashy = {foo: 0, bar: 1, baz: 2}
hashy # => {:foo=>0, :bar=>1, :baz=>2}
note: The Hash key become a
Symbol
note: You will get an error if you use the key that's not a bareword or a String
# Raises SyntaxError (syntax error, unexpected ':', expecting =>):
hashy = {0: 'zero'}
3) String
hashy = {'foo': 0, 'bar': 1, 'baz': 2}
hashy # => {:foo=>0, :bar=>1, :baz=>2}
note: same like number 2. But the key is change to the
String
, instead of symbol.
And you can mix the styles;
hashy = {foo: 0, :bar => 1, 'baz': 2}
hashy # => {:foo=>0, :bar=>1, :baz=>2}
✅ Common use case of using Hash
1) Give names to objects
book = {author: "Daniel J. Levitin", title: "This is Your Brain on Music}"
book # => {:author=>"Daniel J. Levitin", :title=>"This is Your Brain on Music"}
2) 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}
3) initialize an object
class Book
attr_accessor :author, :title
def initialize(hash)
self.author = hash[:author]
self.title = hash[:title]
end
end
book1 = Book.new(author: 'Daniel J. Levitin', title: "'This is Your Brain on Music')"
book1 # => #<Book: @author="Daniel J. Levitin", @title="This is Your Brain on Music">
4) Get the frequency from a list of numbers
numbers = [1, 1, 1, 2, 4, 65, 55, 54, 55]
freq_hash = numbers.each_with_object(Hash.new(0)) { |number, hash| hash[number] += 1 }
puts "#{freq_hash}"
# {1=>3, 2=>1, 4=>1, 65=>1, 55=>2, 54=>1}
Another tricks is using tally
method.
numbers = [1, 1, 1, 2, 4, 65, 55, 54, 55]
numbers.tally
# output
# {1=>3, 2=>1, 4=>1, 65=>1, 55=>2, 54=>1}
note: This is for Ruby 2.7+ only. :P
5) Specify routes
in Ruby on Rails
This is a line from the config/routes.rb
file, the Router in a Rails application:
# defines a GET route mapped to the new action in the PostsController
get '/posts/new', to: 'posts#new'
The example of the above could be rewritten as:
get('/posts/new', { to: 'posts#new' })
The Hash is the second parameter passed to the get(...)
method.
✅ How to Create a Hash
Here are three ways to create a Hash:
1) Method Hash.new
You can create a Hash by calling method Hash.new
h = Hash.new #Define empty hash
h # => {}
h.class # => Hash
h[:first] = 10
h[:second] = 20
h[:third] = 30
puts h # => {:first=>10, :second=>20, :third=>30}
2) Method Hash[]
You can create a Hash by calling 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}
3) Literal form {}
You can create a Hash by using its literal 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}
✅ How to create or update a Hash value
We can use instance method []=
:
h = {foo: 0, bar: 1, baz: 2}
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}
✅ Values in a Ruby Hash
Values can be any Ruby Object
. Including:
- Strings
- Integers & Floats
- Arrays
note Keys are unique, you can only have one
:foo
key, or one:bar
key. When you add the same key twice, the latter will override the former value.
✅ Hash Entry Order
A Hash object presents its entries in the order of their creation.
A new Hash has its initial ordering per the given entries:
h = Hash[foo: 0, bar: 1]
h # => {:foo=>0, :bar=>1}
New entries are added at the end:
h[:baz] = 2
h # => {:foo=>0, :bar=>1, :baz=>2}
Updating a value does not affect the order:
h[:baz] = 3
h # => {:foo=>0, :bar=>1, :baz=>3}
But re-creating a deleted entry can affect the order:
h.delete(:foo)
h[:foo] = 5
h # => {:bar=>1, :baz=>3, :foo=>5}
✅ How to delete a Hash entry
The simplest way is using instance method delete
:
h = {foo: 0, bar: 1, baz: 2}
h.delete(:bar) # => 1
h # => {:foo=>0, :baz=>2}
✅ How to Access Values From a Hash
Hash value/element are access by particular key.
The simplest way to retrieve a Hash value is using instance method []
:
h = {foo: 0, bar: 1, baz: 2}
h[:foo] # => 0
We also can use fetch
method. It does same as the square bracket lookup []
, but it will raise an error
if the key is not defined:
$ irb
> dictionary = { "one" => "satu" } #Malay language ??
> dictionary.fetch("one")
=> "satu"
> dictionary.fetch("two")
KeyError: key not found: "two"
We can prevent this error using the default value.
✅ Extract a nested Hash value
dig
is handy for nested Hash
.
h = { foo: {bar: {baz: 11}}}
h.dig(:foo, :bar, :baz) # => 11
h.dig(:foo, :zot, :xyz) # => nil
g = { foo: [10, 11, 12] }
g.dig(:foo, 1) # => 11
note: This is only for Ruby 2.3+
✅ Hash Keys 101
Hash Key Equivalence
From Documentation: Two objects are treated as the same
hash
key when their hash value is identical and the two objects areeql?
to each other.
irb> g = {foo: 1}
=> {:foo=>1}
irb> h = {foo: 1}
=> {:foo=>1}
irb> g.eql?(h)
=> true
Modifying an Active Hash Key
Modifying a Hash key while it is in use damages the hash index.
This Hash has keys that are Arrays:
a0 = [ :foo, :bar ]
a1 = [ :baz, :bat ]
h = {a0 => 0, a1 => 1}
h.include?(a0) # => true
h[a0] # => 0
a0.hash # => 110002110
Modifying array element a0[0]
changes its hash value:
a0[0] = :bam
a0.hash # => 1069447059
And damages the Hash index:
h.include?(a0) # => false
h[a0] # => nil
You can repair the hash index using method rehash
:
h.rehash # => {[:bam, :bar]=>0, [:baz, :bat]=>1}
h.include?(a0) # => true
h[a0] # => 0
A String
key is always safe. That's because an unfrozen String
passed as a key will be replaced by a duplicated and frozen String:
s = 'foo'
s.frozen? # => false
h = {s => 0}
first_key = h.keys.first
first_key.frozen? # => true
✅ Default values
By default, accessing a key which has not been added to the hash returns nil
, meaning it is always safe to attempt to look up a key's value:
my_hash = {}
my_hash[:name] # => nil
Hashes can also contain keys in strings
. If you try to access them normally it will just return a nil
, instead you access them by their string keys:
my_hash = { "name" => "asyraf" }
my_hash[:name] # => nil
my_hash["name"] # => asyraf
You can retrieve the default value with method default
:
h = Hash.new
h.default # => nil
You can set the default value by passing an argument to method Hash.new
or with method default=
h = Hash.new(100)
h.default # => 100
h.default = 99
h.default # => 99
✅ How to Merge Two Ruby Hashes
I think you can guess the method name :p. Tadaaaa, we will use merge
method.
defaults = { a: 1, b: 2, c: 3 }
preferences = { c: 4 }
defaults.merge!(preferences)
# {:a=>1, :b=>2, :c=>4}
Notice that because keys are unique, newer values overwrite older values.
✅ Multiple Hash values for one key
Malaysia = {
food: [
"Nasi Lemak",
"Roti Canai"
],
city: [
"Kuala Lumpur",
"Malacca City",
"George Town"
]
}
Malaysia[:city][1]
Where Malaysia[:city]
gives you an array & [1]
gives you the 2nd element from that array.
The key is a symbol & the values are arrays. When you access the hash, you get an array back which you access normally, like any other array.
✅ Get All Keys and Values From a Hash
If you want a list of all the keys, good news, there is a method for that!
Here it is:
{ foo: 1, bar: 2 }.keys
# [:foo, :bar]
There’s also a method for values:
{ foo: 1, bar: 2 }.values
# [1, 2]
✅ Check if key exists in hash
If you want to know if a key exists in a hash, use the key?
method.
hash_data = {'Country'=>"Malaysia",'Food'=>"Nasi Lemak",}
puts hash_data.key?("Country") #true
puts hash_data.key?("Code") #false
✅ How to change a Hash to Array
We can do Hash
? Array
. Converting a hash of key/value pairs into an array will produce an array containing nested arrays for pair:
{ :a => 1, :b => 2 }.to_a # => [[:a, 1], [:b, 2]]
In the opposite direction a Hash
can be created from an array
of the same format:
[[:x, 3], [:y, 4]].to_h # => { :x => 3, :y => 4 }
Similarly, Hashes can be initialized using Hash[]
and a list of alternating keys and values:
Hash[:a, 1, :b, 2] # => { :a => 1, :b => 2 }
Or from an array of arrays with two values each:
Hash[ [[:x, 3], [:y, 4]] ] # => { :x => 3, :y => 4 }
Hashes can be converted back to an Array
of alternating keys and values using flatten()
:
{ :a => 1, :b => 2 }.flatten # => [:a, 1, :b, 2]
Super cool
Pretty cool, hah... ?
There are other cool stuff on Ruby Hash. But as i said, this is just a level of most of people dive in.
Maybe for specific tricks like Hash iteration, sorting and other methods for future articles :P.
And probably this is my notes about Ruby Hash, I will add new stuff as I get new knowledge or experience with it.
Thank you for traveling with me ?, I hope you enjoyed the journey ?.
The End
Resources:
This content originally appeared on DEV Community and was authored by Amirul Asyraf
Amirul Asyraf | Sciencx (2021-06-25T01:56:16+00:00) Ruby Hash Method 101. Retrieved from https://www.scien.cx/2021/06/25/ruby-hash-method-101/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.