Skip to content

Instantly share code, notes, and snippets.

@harssh
Created March 18, 2014 05:04
Show Gist options
  • Select an option

  • Save harssh/9613873 to your computer and use it in GitHub Desktop.

Select an option

Save harssh/9613873 to your computer and use it in GitHub Desktop.
7 daily use cases of Ruby Hash
1. How to convert a JSON into a Hash?
You’ve just retrieved a Twitter profile as a JSON:
data = '{
"name": "Aaron Patterson",
"screen_name": "tenderlove",
"location": "Seattle, WA"
}'
You want to transform it as a Hash for easier data manipulation:
require 'json'
profile = JSON.parse(data)
IRB Output:
=> {
"name"=>"Aaron Patterson",
"screen_name"=>"tenderlove",
"location"=>"Seattle, WA"
}
Reference: JSON#parse
2. How to convert a Hash into a JSON?
In your web application, you track the number of signups per day for the current week:
signups_of_the_week = {
monday: 2,
tuesday: 3,
wednesday: 4,
thursday: 20,
friday: 5,
saturday: 2,
sunday: 5
}
You can provide them through an API as JSON data:
require 'json'
signups_of_the_week.to_json
IRB Output:
=> "{\"monday\":2,\"tuesday\":3,\"wednesday\":4,\"thursday\":20,\"friday\":5,\"saturday\":2,\"sunday\":5}"
Reference: JSON#generate
Side note: JSON#pretty_generate is really helpful for pretty printing and debugging.
3. How to set default value for a nested Hash?
You have collection of contacts indexed by name, a nested Hash:
contacts = {
'John' => {
name: 'John',
email: 'john@doe.com'
},
'Freddy' => {
name 'Freddy',
email: 'freddy@mercury.com'
}
}
When working with a contact, you don’t want to check every time if it exists or not. You just want to write:
contacts['Jane'][:email] = 'jane@doe.com'
puts contacts['Jane']
IRB Output:
=> {:name=>"Jane", :email=>"jane@doe.com"}
You can do it by setting a complex value when creating the Hash
contacts = Hash.new do |hsh, key|
hsh[key] = {
name: key,
email: ''
}
end
or later with
contacts.default_proc = Proc.new do |hsh, key|
hsh[key] = {
name: key,
email: ''
}
end
References: Hash#new, Hash#default_proc=
4. How to merge two nested Hashes?
In an online shop, you want to merge a wish list with the current basket, both indexed by product id:
wish_list = {
8 => {
title: "The Color of Magic",
},
42 => {
title: "The Hitch-Hiker's Guide to the Galaxy",
price: 5
}
}
basket = {
8 => {
price: 10
},
1729 => {
title: "Ramanujan: Twelve Lectures on Subjects Suggested by His Life and Work",
price: 28
}
}
With ActiveSupport, you can simply do it with:
require 'active_support/core_ext/hash' # not necessary if in Rails
basket.deep_merge(wish_list)
or without ActiveSupport
def deep_merge(h1, h2)
h1.merge(h2) { |key, h1_elem, h2_elem| deep_merge(h1_elem, h2_elem) }
end
deep_merge(basket, wish_list)
IRB Output:
=> {
8=>{:price=>10, :title=>"The Color of Magic"},
1729=>{:title=>"Ramanujan: Twelve Lectures on Subjects Suggested by His Life and Work", :price=>28},
42=>{:title=>"The Hitch-Hiker's Guide to the Galaxy", :price=>5}
}
References: Hash#merge, Hash#deep_merge
5. How to filter out some keys of a Hash?
You’ve built an histogram of daily sales and stored it in a Hash, the key being the day:
histogram = {
monday: 5,
tuesday: 7,
wednesday: 10,
thursday: 18,
friday: 7,
saturday: 2,
sunday: 0
}
You want to filter out Saturday and Sunday. With ActiveSupport, you can do it as following
require 'active_support/core_ext/hash' # not necessary if Rails
histogram.except(:saturday, :sunday)
or without ActiveSupport
def filter(hsh, *keys)
hsh.dup.tap do |h|
keys.each { |k| h.delete(k) }
end
end
filter(histogram, :saturday, :sunday)
Another clearer implementation is based on reject (credits to Thiago A.):
def filter2(hsh, *keys)
hsh.reject { |k, _| keys.include? k }
end
Note that if you deal with large collection you should benchmark your implementation to select the best one.
IRB Output:
=> {:monday=>5, :tuesday=>7, :wednesday=>10, :thursday=>18, :friday=>7}
Reference: Hash#except, Hash#delete, Hash#reject, Object#dup, Object#tap
6. How to “sort” a Hash by value?
In a dices game, you keep the score per player in a Hash:
scores = {
'The Lady' => 3,
'Fate' => 2,
'Death' => 10
}
You want to to sort them by scores. You can do it with:
leaderboard = scores.sort_by { |_, score| -score }
IRB Output:
=> [["Death", 10], ["The Lady", 3], ["Fate", 2]]
Reference: Enumerable#sort_by
Side note: Hash enumerates their value in their insertion order.
7. How to find the differences between two Hashes?
You regularly retrieve data from RSS feeds and put them into a Hash:
entries = {
1372284000 => "CVE-2013-4073",
1368482400 => "CVE-2013-2065"
}
When doing an update, you get another Hash:
updated_entries = {
1385074800 => "CVE-2013-4164",
1372284000 => "CVE-2013-4073",
1368482400 => "CVE-2013-2065"
}
You want to spot which entries are new so you can for instance send them by email. You can do it with:
new_entries = updated_entries.dup.delete_if {|k| entries.keys.include? k }
but it’s better and clearer to do with
new_entries = updated_entries.reject { |k, _| entries.include? k }
as you benefit from the fast lookup of Hash (Credits to apeiros)
IRB Output:
=> {1385074800=>"CVE-2013-4164"}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment