Ruby Hash Method 101

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 ha…


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

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

Back to the top

✅ 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.

Back to the top

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

Back to the top

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

Back to the top

✅ 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.

Back to the top

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

Back to the top

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

Back to the top

✅ 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.

Back to the top

✅ 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+

Back to the top

✅ 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 are eql? 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

Back to the top

✅ 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

Back to the top

✅ 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.

Back to the top

✅ 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.

Back to the top

✅ 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]

Back to the top

✅ 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

Back to the top

✅ 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]

Back to the top

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:

1, 2, 3, 4, 5, 6, 7


This content originally appeared on DEV Community and was authored by Amirul Asyraf


Print Share Comment Cite Upload Translate Updates
APA

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/

MLA
" » Ruby Hash Method 101." Amirul Asyraf | Sciencx - Friday June 25, 2021, https://www.scien.cx/2021/06/25/ruby-hash-method-101/
HARVARD
Amirul Asyraf | Sciencx Friday June 25, 2021 » Ruby Hash Method 101., viewed ,<https://www.scien.cx/2021/06/25/ruby-hash-method-101/>
VANCOUVER
Amirul Asyraf | Sciencx - » Ruby Hash Method 101. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/06/25/ruby-hash-method-101/
CHICAGO
" » Ruby Hash Method 101." Amirul Asyraf | Sciencx - Accessed . https://www.scien.cx/2021/06/25/ruby-hash-method-101/
IEEE
" » Ruby Hash Method 101." Amirul Asyraf | Sciencx [Online]. Available: https://www.scien.cx/2021/06/25/ruby-hash-method-101/. [Accessed: ]
rf:citation
» Ruby Hash Method 101 | Amirul Asyraf | Sciencx | 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.

You must be logged in to translate posts. Please log in or register.