Now Reading
Ruby’s Hash is a Swiss-Military Knife

Ruby’s Hash is a Swiss-Military Knife

2023-08-20 15:36:30

After I used to program in C# (and even Java earlier than that), one of many subjects that all the time puzzled me was when to make use of which class. There are actually hundreds and hundreds of courses within the core language, framework, and the usual library. For instance, listed below are the 5 sorts that implement the IDictionary interface in C#.

  • Hashtable
  • SortedList
  • SortedList<TKey, TValue>
  • Dictionary<TKey, TValue>
  • ConcurrentDictionary<TKey, TValue>

After all, there is a use for every, and I do not doubt the selections of the language and framework creators (enormous respect for Anders Hejlsberg, creator of C#). However as a programmer constructing run-of-the-mill CRUD net functions, having so many decisions could be actually daunting and complicated. When do you select which sort? What in case you made a incorrect selection?

In distinction, Ruby has a single Hash class to handle key-value pairs. It is a very versatile knowledge construction. It may possibly act as an information object, a dictionary, a hash desk, a sorted listing, and way more. Like nearly every part in Ruby, it is a sharp knife that you need to use to chop your self, however may use to cook dinner nice meals; I imply, write good applications.

This put up explores the Hash knowledge construction in-depth, and lists a few of the obscure however helpful operations in day-to-day programming.

What’s a Hash?

A Hash is a general-purpose knowledge construction for storing pairs of knowledge. In programming phrases, a Hash is an information kind that associates (maps) values to keys.

This is a easy Ruby hash that has two keys, :title and :worth (each are Ruby symbols), with the values 'ebook' and 10 respectively.

product = { title: 'ebook', worth: 10 }

An vital factor to notice with the above syntax is that it is really a shorthand that was added in newer variations of Ruby, to simplify utilizing image keys.

This is the unique hash syntax for a similar code above:

product = { :title => 'ebook', :worth => 10 }

On this case, the keys are explicitly created as Ruby symbols, i.e. :title and :worth.

Along with symbols, Ruby hashes can have nearly any object as the important thing, e.g. strings and integers. If you wish to have another values as keys, then you must use the older syntax, which makes use of arrows.

# older syntax

knowledge = { "product" => "iPhone", 600 => "Value (in {dollars})" }

values = { 0 => 'first', 1 => 'second' }  # simply use arrays as an alternative

You may also outline user-defined objects as keys. However it’s uncommon, and deserves a weblog put up of its personal. Try the documentation to study extra.

A Hash is much like an Array, however shops an inventory of key-value pairs. In an array, every ingredient has a positional index, however a Hash key could be something, and the important thing needs to be distinctive, and every key has a single mapped worth.

????

Consider the hash as a operate whose enter is a key, and output is the information or the worth saved for that key. 

A special method to consider a Hash as a chest with drawers which have a singular label (key) on them, and might retailer recordsdata (values). Everytime you want a file (worth), simply open the drawer with correct label.

drawers
drawers

Now, a drawer cannot have duplicate labels, proper? How would you recognize which drawer to open? Equally, in case you attempt to create a hash with duplicate keys, Ruby will warn you and solely retailer the final key worth pair.

particular person = { title: 'Akshay', title: 'AK' }

# Output

warning: key :title is duplicated and overwritten on line 20

To retrieve the information, use the array notation. If the important thing exists, it would return the worth, in any other case it would return nil.

particular person[:name]
=> "Akshay"

knowledge["item"]
=> "iPhone"

knowledge[100]
=> "One Hundred"

Alternatively, you need to use the fetch technique on a hash, as follows:

particular person.fetch(:title)

Favor fetch over []

A pleasant factor about fetch is that if a key would not exist, it would instantly let you recognize, as an alternative of returning nil. This can stop null reference errors additional down the chain.

particular person.fetch(:names)

# `fetch': key not discovered: :names (KeyError)
# Did you imply?  :title

For instance, in case you use [] to entry a non-existent key, you will not understand it till you attempt to name a technique on the nil object and it fails.

props = { width: '60', top: '40' }

form = props[:shape]  # nil

form.print 

# Output

primary.rb:24:in `<primary>': non-public technique `print' known as for nil:NilClass (NoMethodError)

Delete a Key

To delete a key, merely name the delete technique on hash, passing the title of the important thing.

product = { title: 'iPhone', worth: '500' }

product.delete(:worth)  # "500"
product                 # { :title => "iPhone" }

For those who attempt to delete a non-existent key, Ruby will not complain.

Nested Hash

A hash could be nested. To entry the inside values, you need to use the brackets, or use the dig technique.

product = { telephone: { mannequin: 'iPhone' } }

places product[:phone][:model]     # iPhone
places product.dig(:telephone, :mannequin) # iPhone

Default Values

If a hash would not comprise the important thing, it returns nil. Nonetheless, you possibly can set the default worth for the hash utilizing its default property. Alternatively, you may also use a block when initializing the hash object.

particular person = { title: "Akshay", age: 31 }

particular person[:city]         # nil
particular person.default = "-"  # "-"
particular person[:city]         # "-"

particular person = Hash.new { |hash, key| "Default worth for #{key}" }
particular person[:city]         # "Default worth for metropolis"

If you have already got a bunch of variables, you possibly can create a brand new hash with these variables as keys, as follows:

width="10px"
top="20px"
border="rounded"

properties = { width:, top:, border: }

places properties  # {:width=>"10px", :top=>"20px", :border=>"rounded"}

Iterating Over a Hash

The Hash class contains the Enumerable module. Moreover, a hash preserves the order of the entries. This successfully makes a hash act like an inventory (or an array). That is helpful whenever you need to loop over a hash with every, each_key, each_pair, each_value, keys and values. Let’s take a look at every technique together with an instance.

The every technique helps you to loop over the key-value pair. For those who present a single argument to the block, the pair might be handed as an array.

properties = { width: '30px', top: '10px', coloration: 'inexperienced' }

properties.every do |prop|
  p prop
finish

# Output

[:width, "30px"]
[:height, "10px"]
[:color, "green"]

For those who present two arguments, the key-value pair might be unfold over these two. If you wish to be extra expressive, use each_pair, which works the identical.

properties = { width: '30px', top: '10px', coloration: 'inexperienced' }

properties.every do |prop, val|
  places "#{prop}: #{val}"
finish

# OR
properties.each_pair do |prop, val|
  places "#{prop}: #{val}"
finish

# Output

width: 30px
top: 10px
coloration: inexperienced

To entry keys and values individually, use both keys, each_key, values or each_value technique, which work as you anticipate.

properties = { width: '30px', top: '10px', coloration: 'inexperienced' }

p properties.keys
p properties.values

properties.each_key key
properties.each_value worth

# Output

[:width, :height, :color]
width
top
coloration

["30px", "10px", "green"]
30px
10px
inexperienced

Passing Hash to Features

You possibly can go a hash to a operate (however you in all probability knew that).

def process_payment(fee)
  print fee.keys  # [:product, :price, :apple_care]
finish

fee = {
  product: 'iPhone 13 mini',
  worth: 800.00,
  apple_care: false
}

process_payment(fee)

However do you know that the curly braces could also be omitted when the final argument in a technique name is a Hash?

def process_payment(person, fee)
  places person
  p fee.keys
finish

person="Akshay"
process_payment(person, product: 'iPhone 13 mini', worth: 800.00, apple_care: false)

# Output

Akshay
[:product, :price, :apple_care]

That mentioned, simply because you possibly can, does not imply you must. In reality, this behavior is deprecated within the newest variations of Ruby. A greater resolution is to make use of the double-splat operator (**), which we’ll see subsequent.

For a fantastic instance demonstrating why it was deprecated, please try this comment on Hacker Information.

Double Splat Operator

This in all probability deserves a separate weblog put up of its personal, however you need to use the double splat operator to ‘unpack’ hashes into different hashes.

properties = { 
  width: '30px', 
  top: '10px'
}

type = { **properties, border: 'none' }

p type

# Output

{:width=>"30px", :top=>"10px", :border=>"none"}

Moreover, you may also use it to seize all key phrase arguments to a technique (which will also be a easy hash).

def process_payment(person, **fee)
  places person
  p fee.keys
finish

person="Akshay"
process_payment(person, product: 'iPhone 13 mini', worth: 800.00, apple_care: false)

# Output

Akshay
[:product, :price, :apple_care]

Helpful Hash Strategies

On this part, we’ll check out a few of the widespread however helpful strategies on Hash. For all of the examples that observe, we’ll use following properties hash.

properties = { 
  width: '30px', 
  top: '10px', 
  coloration: 'inexperienced',
  show: :flex,
  choices: nil
}

Returns true if any key-value pair satisfies a given situation. In any other case, returns false.

properties.any?  worth == :flex   # true

Returns a duplicate of the hash with all nil-valued entries eliminated. The unique hash is just not modified. To change the unique hash, use compact!.

properties.compact

# {:width=>"30px", :top=>"10px", :coloration=>"inexperienced", :show=>:flex}

Returns true if there are not any hash entries, false in any other case.

properties.empty?  # false

h = {}
h.empty?           # true

Hash.new.empty?    # true

Merges one other hash into this hash. You possibly can merely present the key:worth pairs as argument, too.

properties.merge({ radius: '5px' })

# OR

properties.merge(radius: '5px')

# {:width=>"30px", :top=>"10px", :coloration=>"inexperienced", :show=>:flex, :choices=>nil, :radius=>"5px"}

Returns true provided that the next circumstances are true:

  1. obj is a Hash
  2. hash and obj have the identical keys (order would not matter)
  3. For every key, hash[key].eql? obj[key]

That is totally different from equal? which returns true if and provided that each values consult with the identical object.

new_props = { width: '30px', top: '10px', coloration: 'inexperienced', show: :flex, choices: nil }

# false, as they're totally different objects
properties.equal?(new_props)

# true, their form is identical
properties.eql?(new_props)

Returns a brand new Hash with out the entries for the given keys

properties.besides(:show)
properties.besides(:show, :choices)

# Output

{:width=>"30px", :top=>"10px", :coloration=>"inexperienced", :choices=>nil}
{:width=>"30px", :top=>"10px", :coloration=>"inexperienced"}

That is much like besides, within the sense that it removes the keys from the hash. The primary distinction is you could go a block to it, which is executed for every key-value pair. All pairs satisfying the situation might be eliminated.

properties.reject  worth == :flex 

# {:width=>"30px", :top=>"10px", :coloration=>"inexperienced", :choices=>nil}

As all the time, it will not change the unique hash, for which you have to make use of reject!.

These strategies selectively filter key-value pairs satisfying a given situation and return a brand new hash.

properties.filter  worth == :flex 

# {:show=>:flex}
  • fetch_values(*keys) OR hash.values_at(:k1, :k2)

Returns an array containing the values for the given keys.

See Also

Moreover, you possibly can go a block to fetch_values. It is going to be known as for every lacking key. The return worth of the block is used for the important thing’s worth.

properties.fetch_values(:width, :top) # ["30px", "10px"]
properties.fetch_values(:top, :radius)  key.to_s  # ["10px", "radius"]

properties.values_at(:width, :top) # ["30px", "10px"]
  • has_key?, member?, embrace?, and key?

All of those strategies examine if the hash incorporates the given key.

properties.has_key? :width  # true
properties.key?     :form  # false
properties.member?  :coloration  # true
properties.embrace? :object # false

Verify if the hash incorporates the given worth.

properties.has_value? 'inexperienced'  # true
properties.worth? :flex        # true
properties.worth? :random      # false

Returns the variety of entries within the hash.

properties.size # 5

properties.measurement # 5

It returns the variety of entries identical to size and measurement, however it additionally takes a block and returns the depend of entries satisfying the block situation.

properties.depend # 5

properties.depend ok, v # 2

Returns a brand new hash containing the entries for the given keys.

properties.slice(:width, :top)

# Output

{:width=>"30px", :top=>"10px"}

Returns a brand new hash with the values reworked by a block that accepts every worth. It would not modify the unique hash. For altering the unique hash, use transform_values! technique.

knowledge = { a: 100, b: 200 }

new_data =  knowledge.transform_values v

new_data  # {:a=>200, :b=>400}
knowledge      # {:a=>100, :b=>200}

Returns an array that could be a 1-dimensional flattening of the hash.

properties.flatten

# [:width, "30px", :height, "10px", :color, "green", :display, :flex, :options, nil]

I am going to cease now, however there’re an entire lot of different operations you might carry out on a hash. Try the Hash and Enumerable documentation for a complete reference.

By the best way, in case you discovered this text helpful, you would possibly get pleasure from these:

How to Access Hash Values with Methods Using OrderedOptions

Have you ever wanted to create a hash where you could access the values like methods on an object? The OrderedOptions class in Rails lets you do just that. This post shows you how. We’ll also explore how Rails implements this feature using Ruby’s metaprogramming features.

How to Access a Hash with both String and Symbol Keys in Rails

Sometimes, you receive a hash key as a method parameter or via user input, and you want to make your hash understand that key as-is, without worrying if it’s a string or a symbol. A good example is the params hash in Rails. You can access it using either a

How to Convert a Ruby Object to Hash

Let’s say you have a Product object with properties @name = “Table” & @price = 10. What’s the best way in Rails to convert this object to the Hash { name: “Table”, price: 10 }? Here’re a few different ways to achieve this. The as_json Method (Rails) The as_json method converts


That is a wrap. I hope you favored this text and also you discovered one thing new. For those who’re new to the weblog, try the start here web page for a guided tour or browse the full archive to see all of the posts I’ve written to date.

As all the time, when you’ve got any questions or suggestions, did not perceive one thing, or discovered a mistake, please go away a remark under or send me an email. I stay up for listening to from you.

If you would like to obtain future articles straight in your e-mail, please subscribe to my blog. For those who’re already a subscriber, thanks.

Source Link

What's Your Reaction?
Excited
0
Happy
0
In Love
0
Not Sure
0
Silly
0
View Comments (0)

Leave a Reply

Your email address will not be published.

2022 Blinking Robots.
WordPress by Doejo

Scroll To Top